cookie
在上节课,我们简单了解了登录过程,但是很明显,每次都需要登录,但是在平常逛网站的只需要登录一次,那么网站是如何记录登录信息的呢?
有没有什么办法可以让浏览器记住登录信息,下次再次打开的时候,可以自动登录呢?
设置cookie与获取cookie
import sys
import time
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
from tornado.web import RequestHandler
from tornado.options import define,options
import util.ui_modules
import util.ui_methods
# import time
from data.connect import session
from data.user_modules import UserDetails, User
define('port',default=8080,help='run server',type=int)
class MainHandler(RequestHandler):
def get(self):
self.write('cookie')
self.set_cookie('cookie_test','aqweqwas')
self.set_cookie('cookie_test2','aqweqwas2',expires=time.time()+60) #设置过期时间
self.set_cookie('cookie_test3','aqweqwas3',expires_days=1) #设置过期天数
self.set_cookie('cookie_test4','aqweqwas4',path='/') #设置cookie路径
self.set_cookie('cookie_test5','aqweqwas5',httponly=True) #设置后js代码获取不到此cookie值
self.set_cookie('cookie_test6','aqweqwas6',max_age=120,expires=time.time()+60) #设置过期时间max_age的优先级大于expires
self.set_secure_cookie('cookie_test7','aqweqwas7',max_age=120,expires=time.time()+60) #设置加密cookies
class GetHandler(RequestHandler):
def get(self):
self.write('get_cookie')
self.write('<br>')
cookie_name = self.get_cookie('cookie_test4')
cookie_name2 = self.get_secure_cookie('cookie_test7')
self.write(cookie_name)
self.write('<br>')
self.write(cookie_name2)
application = tornado.web.Application(
handlers=[
(r'/',MainHandler),
(r'/get',GetHandler),
],
debug=True,
template_path = 'templates',
static_path='static',
# autoescape = None, #全局取消转义
ui_methods=util.ui_methods,
ui_modules=util.ui_modules,
cookie_secret ='qwe123', #cookie加盐
)
if __name__ == '__main__':
tornado.options.parse_command_line()
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
登录验证:
第一步:导入装饰器
from tornado.web import authenticated
第二步:声明 BaseHandler
class BaseHandler(RequestHandler):
def get_current_user(self):
current_user = self.get_secure_cookie('user_ID')
if current_user:
return current_user
return None
第三步:配置登录路由
login_url = '/login'
第四步:装饰需要验证的请求
class BuyHandler(BaseHandler):
@authenticated
def get(self):
self.write('嗨,小可爱!')
在完成登录之后,再来看看,我们从一个路由跳转到登录页面之后,再完成登录之后,该如何跳转到之前的页面呢?
第一步:获取之前路由
class LoginHandler(BaseHandler):
def get(self):
next_name = self.get_argument('next','')
self.render('in_out.html',nextname=next_name)
在使用 authenticated 之后,如果验证不成功,会自动跳转到登录路由,并且在 URL 后面加上 next 参数,next 参数的参数值就是之前的路由
第二步:修改模板文件
<form method="post" action="/login?next={{ nextname }}">
在模板中添加 next 参数,并且参数值为之前的路由
第三步:修改post方法
def post(self):
'''验证逻辑'''
user = self.get_argument('name',None)
password = self.get_argument('password',None)
next_name = self.get_argument('next','')
print(next_name)
# username = session.query(User).filter(User.username == user).first()
username = User.get_name(user)
print(username)
if username and password == username.password:
#如果判断用户可以登录,我们设置这样一个加密的cookie进去
self.set_secure_cookie('user_ID',user)
self.redirect(next_name)
else:
self.write('登录失败')
获取之前的页面的路由
当登录验证通过之后,设置加密的 cookie ,并跳转到之前的路由
完整的python代码与模板html代码如下:
import sys
import time
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
from tornado.web import RequestHandler,authenticated
from tornado.options import define,options
import util.ui_modules
import util.ui_methods
# import time
from data.connect import session
from data.user_modules import UserDetails, User
define('port',default=8080,help='run server',type=int)
class BaseHandler(RequestHandler):
def get_current_user(self):
current_user = self.get_secure_cookie('user_ID')
if current_user:
return current_user
return None
class BuyHandler(BaseHandler):
@authenticated
def get(self):
self.write('嗨,小可爱!')
#第一,如果有参数next,肯定是没登录的时候
#没登录,会跳转到/login,app里面设置的
#在login里面,form表单没提交之前,get里面获取一下这个值
#在获取出来之后,吧这个值传到post请求里面
#post获取这个值,此值就是一个url
#直接跳转到此url
class LoginHandler(BaseHandler):
def get(self):
next_name = self.get_argument('next','')
self.render('in_out.html',nextname=next_name)
def post(self):
'''验证逻辑'''
user = self.get_argument('name',None)
password = self.get_argument('password',None)
next_name = self.get_argument('next','')
print(next_name)
# username = session.query(User).filter(User.username == user).first()
username = User.get_name(user)
print(username)
if username and password == username.password:
#如果判断用户可以登录,我们设置这样一个加密的cookie进去
self.set_secure_cookie('user_ID',user)
self.redirect(next_name)
else:
self.write('登录失败')
application = tornado.web.Application(
handlers=[
(r'/buy',BuyHandler),
(r'/login',LoginHandler),
],
debug=True,
template_path = 'templates',
static_path='static',
# autoescape = None, #全局取消转义
ui_methods=util.ui_methods,
ui_modules=util.ui_modules,
cookie_secret ='qwe123', #cookie加盐
login_url = '/login'
)
if __name__ == '__main__':
tornado.options.parse_command_line()
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
in_out.html代码如下:
<!DOCTYPE html>
<html lang="en">
<head>
<meta charset="UTF-8">
<title>tornado</title>
</head>
<body>
<form method="post" action="/login?next={{ nextname }}">
<p>用户名<input type="text" name="name"></p>
<p>密码<input type="password" name="password"></p>
<input type="submit">
</form>
</body>
</html>
session
通过刚才的学习,可以用了解到 cookie 中的信息可以用来保存用户的登录信息,但是coolkie 是很容易被拦截的,所有其中必定不能有用户的任何私密信息,那么又有什么办法可以让服务器保存用户的登录信息,但是cookie中又不会有用户的任何信息呢?
第一步:安装模块
pip install pycket #tornado中用于连接redis的模块
pip install redis
第二步:导入模块
from pycket.session import SessionMixin
第三步:继承SessionMixin
class BaseHandler(tornado.web.RequestHandler, SessionMixin):
第四步:在application 中添加配置
配置 redis 的相关信息
配置 cookie 的过期时间
pycket = {
'engine':'redis',
'storage':{
'host':'localhost',
'port':6379,
'db_sessions':5,
'max_connections':2**10,
},
'cookies':{
'expires_days':7
}
}
第五步:改设置cookie为设置session
self.session.set('user_ID',user)
第六步:改获取cookie为获取session
current_user = self.session.get('user_ID')
完整代码如下:
import sys
import time
import tornado.web
import tornado.ioloop
import tornado.httpserver
import tornado.options
from tornado.web import RequestHandler,authenticated
from tornado.options import define,options
from pycket.session import SessionMixin
import util.ui_modules
import util.ui_methods
# import time
from data.connect import session
from data.user_modules import UserDetails, User
define('port',default=8080,help='run server',type=int)
class BaseHandler(RequestHandler,SessionMixin):
def get_current_user(self):
current_user = self.session.get('user_ID')
if current_user:
return current_user
return None
class BuyHandler(BaseHandler):
@authenticated
def get(self):
self.write('嗨,小可爱!')
#第一,如果有参数next,肯定是没登录的时候
#没登录,会跳转到/login,app里面设置的
#在login里面,form表单没提交之前,get里面获取一下这个值
#在获取出来之后,吧这个值传到post请求里面
#post获取这个值,此值就是一个url
#直接跳转到此url
class LoginHandler(BaseHandler):
def get(self):
next_name = self.get_argument('next','')
self.render('in_out.html',nextname=next_name)
def post(self):
'''验证逻辑'''
user = self.get_argument('name',None)
password = self.get_argument('password',None)
next_name = self.get_argument('next','')
print(next_name)
# username = session.query(User).filter(User.username == user).first()
username = User.get_name(user)
print(username)
if username and password == username.password:
#如果判断用户可以登录,我们设置这样一个加密的cookie进去
# self.set_secure_cookie('user_ID',user)
self.session.set('user_ID',user)
self.redirect(next_name)
else:
self.write('登录失败')
application = tornado.web.Application(
handlers=[
(r'/buy',BuyHandler),
(r'/login',LoginHandler),
],
debug=True,
template_path = 'templates',
static_path='static',
# autoescape = None, #全局取消转义
ui_methods=util.ui_methods,
ui_modules=util.ui_modules,
cookie_secret ='qwe123', #cookie加盐
login_url = '/login',
pycket = {
'engine':'redis',
'storage':{
'host':'localhost',
'port':6379,
'db_sessions':5,
'max_connections':2**10,
},
'cookies':{
'expires_days':7
}
}
)
if __name__ == '__main__':
tornado.options.parse_command_line()
http_server = tornado.httpserver.HTTPServer(application)
http_server.listen(options.port)
tornado.ioloop.IOLoop.current().start()
XSRF:防止跨域请求伪造
使用session可以保证用户信息不被cookie泄漏,那如果如果攻击者不想获取用户信息,只是在提交 form 表单时攻击,该怎么防范呢?
模板添加
{% module xsrf_form_html() %}
代码如下:
<body>
{% module xsrf_form_html() %}
<form method="post" action="/login?next={{ nextname }}">
<p>用户名<input type="text" name="name"></p>
<p>密码<input type="password" name="password"></p>
<input type="submit">
</form>
</body>
Tornado 有内建的 XSRF 的防范机制,要使用此机制,只需要在模板中添加如上代码
页面效果显示:
生成一段关于xsrf的随机字符串,防止伪造
来源:oschina
链接:https://my.oschina.net/u/4314104/blog/3584549