Tornado-Lesson09-cookie登录验证-session和XSRF
一、cookie
1.cookie的概念
指服务器为了识别用户身份,缓存在浏览器本地的数据;多用于保存登录状态
2.cookie的使用
1)设置cookie
set_cookie(name, value)
set_cookie(name, value, expires = time.time()+n) 设置过期时间为n秒
set_cookie(name, value, expires_days = n) 设置有效期,n天
set_cookie(name, value, max_age = n, expires = time.time()+n) max_age;min_age限制有效期最大和最小时间
set_cookie(name, value, path = '/’) 设置路径
set_cookie(name, value, httponly = True) 设置httponly = True,该cookie无法被js获取
self.set_secure_cookie(name, value) 设置一个加密的cookie,需要在application中设置cookie_secret
self.clear_cookie(name) 删除cookie,调用可以看到cookis信息为空
self.clear_all_cookies() 删除此请求发送的全部cookie
注:set_cookie中value不能包含空格,否则报错
2)获取cookie
self.get_cookie(name)
self.get_secure_cookie(value)
注:get_secure_cookie获取的cookie是bytes类型,get_cookie获取的是str类型
二、登录验证
1.利用cookie登录验证
1)导入装饰器
from tornado.web import authenticated
2)声明BaseHandler
class BaseHandler(tornado.web.RequestHandler):
def get_current_user(self):
current_user = self.get_secure_cookie('cookie_name')
if current_user:
return current_user
return None
3)配置路由
在applaction中添加 login_url = '/login'
4)调用装饰器验证请求
继承BaseHandler,并使用装饰器@authenticated
class BuyHandler(BaseHandler):
@authenticated
def get(self):
self.write('BuyHandler')
这样,当路由跳转BuyHandler时候,先判断有没有cookie,如果有,则正常显示页面。如果没有cookie信息,则跳转到login_url所配置的路由
2.从某一路由跳转到登录页面的完整cookis验证流程
cookie_test.py
import tornado.ioloop import tornado.web import tornado.httpserver import tornado.options import json import time import util.ui_methods import util.ui_modules from tornado.options import define, options from data.user_module import User from tornado.web import authenticated import data print(dir(data)) print(data.name) define('port', default=8080, help='run port', type=int) define('version', default='0.01', help='version', type=str) class BaseHandler(tornado.web.RequestHandler): def get_current_user(self): current_user = self.get_secure_cookie('ID') if current_user: return current_user return None class SetCookieHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): self.set_cookie('cookie_test', 'this_is_cookie_test') self.set_cookie('cookie_test_1', 'this_is_cookie_test_1', expires_days=1) #设置有效期,生成时间+n秒 self.set_cookie('cookie_test_2', 'this_is_cookie_test_2', expires_days=1) #设置有效期1天 self.set_cookie('cookie_test_3', 'this_is_cookie_test_3', expires_days=1, path='/test/') # 设置有路径 self.set_cookie('cookie_test_4', 'this_is_cookie_test_4', expires_days=1, httponly=True) # js不可获取 self.set_cookie('cookie_test_5', 'this_is_cookie_test_5', max_age= 120, expires=time.time() + 180) #限制最大时间 self.set_cookie('cookie_test_6', 'this_is_cookie_test_6', max_age=120, expires=time.time() + 60) # 限制最大时间 self.set_secure_cookie('cookie_test_7', 'this_is_cookie_test_7') # self.clear_cookie('cookie_test') # self.clear_all_cookies() class GetCookieHandler(tornado.web.RequestHandler): def get(self): get_cookie1 = self.get_cookie('cookie_test_1') get_cookie2 = self.get_cookie('cookie_test_2') get_cookie3 = self.get_secure_cookie('cookie_test_7') print(type(get_cookie1)) print(type(get_cookie2)) print(type(get_cookie3)) self.write(get_cookie1 + '<br>' + get_cookie2 + '<br>' + str(get_cookie3, encoding = "utf-8")) class LoginHandler(tornado.web.RequestHandler): def get(self, *args, **kwargs): nextname = self.get_argument('next', '') self.render('login.html', nextname=nextname, error = None) def post(self, *args, **kwargs): nextname = self.get_argument('next', '') user = self.get_argument('name', '') username = User.by_name(user) password = self.get_argument('password', '') if username and password==username.password: self.set_secure_cookie('ID', username.username) # self.render('login_success.html', # username = username.username # ) self.redirect(nextname) else: self.render('login.html', nextname=nextname, error = '用户名和密码错误') class BuyHandler(BaseHandler): @authenticated def get(self, *args, **kwargs): self.write('这个问题冲钱就能解决') application = tornado.web.Application( handlers=[ (r"/login", LoginHandler), (r"/buy", BuyHandler), (r"/set", SetCookieHandler), (r"/get", GetCookieHandler) ], debug=True, static_path = 'static', template_path = 'templates', ui_methods=util.ui_methods, # ui_modules=util.ui_modules, cookie_secret = 'abcdefg', login_url = '/login', ui_modules={'UiModule':util.ui_modules.UiModule} ) if __name__ == '__main__': tornado.options.parse_command_line() print(options.port) print(options.version) http_server = tornado.httpserver.HTTPServer(application) http_server.listen(options.port) tornado.ioloop.IOLoop.instance().start()
login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Tornado</title> </head> <body> {% if error %} 用户名或密码错误 {% else %} Welcome! {% end %} <form method="post" action="/login?next={{ nextname }}"> <p>用户名<br><input type="text" name="name"></p> <p>密码<br><input type="password" name="password"></p> <input type="submit"> </form> </body> </html>
看上面代码,当输入网址,跳转到/buy路由时,BuyHandler继承了BaseHandler并使用了装饰器@authenticated,由以下该源码装饰器可以看出,该装饰器作用是判断是否有cookie;
如果有,则正常返回get请求。
如果没有则返回applaction中login_url配置的路由,并在后面加上"?next=next_url",next_url就是之前跳转过来的路由"/buy".
def authenticated(method): """Decorate methods with this to require that the user be logged in. If the user is not logged in, they will be redirected to the configured `login url <RequestHandler.get_login_url>`. If you configure a login url with a query parameter, Tornado will assume you know what you're doing and use it as-is. If not, it will add a `next` parameter so the login page knows where to send you once you're logged in. """ @functools.wraps(method) def wrapper(self, *args, **kwargs): if not self.current_user: if self.request.method in ("GET", "HEAD"): url = self.get_login_url() if "?" not in url: if urlparse.urlsplit(url).scheme: # if login url is absolute, make next absolute too next_url = self.request.full_url() else: next_url = self.request.uri url += "?" + urlencode(dict(next=next_url)) self.redirect(url) return raise HTTPError(403) return method(self, *args, **kwargs) return wrapper
当没有cookie时候的运行结果:
当有cookie,正常跳转到写入数据
三、登录验证
四、XSRF