一、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