flask九:cookie、session
一.会话技术
二.cookie示例
1.登录页面,templates/login.html
<!DOCTYPE html> <html lang="en"> <head> <meta charset="UTF-8"> <title>Login</title> </head> <body> <form action="{{ url_for('first_blue.login') }}"> <span>用户名:</span> <input type="text" name="username" placeholder="请输入用户名"> <br> <button>登录</button> </form> </body> </html>
2.服务器response设置cookie的key-value值并返回给客户端,客户端保存response中设置的cookie的key-value值到在本地浏览器缓存中
/login地址,GET请求返回前端页面(表单页面),POST请求返回cookie(提交表单)
@first_blue.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') elif request.method == 'POST': username = request.form.get("username") response = Response("登录成功%s" % username) response.set_cookie("username", username) return response return "no support"
3.使用cookie跨页面(跨请求)
在下次请求(跨请求)时,浏览器会携带cookie中key-value值一起发起请求,服务器从request请求头中读取cookie中的username。服务器得到了username,用户信息得到验证,跨页面完成验证。
在浏览器中,可以看到username: ***的cookie值
@first_blue.route('/mime') def mine(): username = request.cookies.get("username") return "欢迎回来: %s" % username
三.session示例
1.登录页面,templates/login.html
2.服务器端app.config中设置secret_key。secret_key就是服务器中存储的数据。
这里使用封装后的settings.py/Config类,去配置app.config,因此在Config类中添加secret_key
class Config: DEBUG = False TESTING = False SQLALCHEMY_TRACK_MODIFICATIONS = False SECRET_KEY = "abc123"
3.服务器端response返回cookie时给客户端,使用session生成cookie中的key-value值。
服务器端保存session的key和value,response将session的key返回客户端,客户端保存session的key。
@first_blue.route('/login', methods=['GET', 'POST']) def login(): if request.method == 'GET': return render_template('login.html') elif request.method == 'POST': username = request.form.get("username") response = Response("登录成功%s" % username) # response.set_cookie("username", username) session['username'] = username return response return "no support"
3.使用session跨页面(跨请求)
从浏览器的session中,获取username
@first_blue.route('/mime') def mine(): # username = request.cookies.get("username") username = session.get("username") return "欢迎回来: %s" % username
四.session源码解读
Flask的默认session利用了Werkzeug的SecureCookie,把信息做序列化(pickle)后编码(base64),放到cookie里了。
过期时间是通过cookie的过期时间实现的。
为了防止cookie内容被篡改,session会自动打上一个叫session的hash串,这个串是经过session内容、SECRET_KEY计算出来的,
看得出,这种设计虽然不能保证session里的内容不泄露,但至少防止了不被篡改。
app = Flask(__name__) if __name__ == '__main__': #这里会执行Flask.__call__() app.run() #这里的__call__方法 def __call__(self, environ, start_response): """Shortcut for :attr:`wsgi_app`.""" return self.wsgi_app(environ, start_response) #返回的wsgi_app def wsgi_app(self, environ, start_response): #这里返回一个上下文对象 ctx = self.request_context(environ) #将上下文对象放入{'ident':{'stack':[]}}的列表中,具体分析见http://blog.csdn.net/qq_33733970/article/details/78984955 ctx.push() #让我们看下self.request_context中具体做了什么? def request_context(self, environ): return RequestContext(self, environ) #我们看下这个RequestContext中都有什么? class RequestContext(object): def __init__(self, app, environ, request=None): self.app = app #首先处理了request, if request is None: ###request_class = Request request = app.request_class(environ) self.request = request self.url_adapter = app.create_url_adapter(self.request) self.flashes = None #定义了一下session,这时的session为None self.session = None #现在我们看下ctx.push()中做了什么 def push(self): #处理session核心代码 self.session = self.app.open_session(self.request) if self.session is None: #如果session为None:返回NullSession self.session = self.app.make_null_session() #看下它是怎么处理session的: #我们看下self.session = self.app.open_session(self.request)是什么? #调用了app的open_session: def open_session(self, request): #SecureCookieSessionInterface().open_session() return self.session_interface.open_session(self, request) #看下session_interface是什么鬼? session_interface = SecureCookieSessionInterface() #接着看下open_session内部做了什么? def open_session(self, app, request): #获取加解密对象 s = self.get_signing_serializer(app) if s is None: return None # 从cookies中获取cookie的名字:'session' val = request.cookies.get(app.session_cookie_name) if not val: #如果val为空,则返回SecureCookieSession对象,相当于{} #session_class = SecureCookieSession return self.session_class() max_age = total_seconds(app.permanent_session_lifetime) try: # 解密返回原始数据 data = s.loads(val, max_age=max_age) #session_class = SecureCookieSession相当于{},根据代码追溯可以发现,基类继承dict #"""Base class for sessions based on signed cookies.""" #翻译一下:基于加密cookies的session基类 return self.session_class(data) except BadSignature: return self.session_class() #这里session已经处理完毕,接着我们回去看 def wsgi_app(self, environ, start_response): ctx = self.request_context(environ) ctx.push() error = None try: try: # 处理视图函数 response = self.full_dispatch_request() except Exception as e: error = e response = self.handle_exception(e) except: error = sys.exc_info()[1] raise return response(environ, start_response) finally: if self.should_ignore_error(error): error = None ctx.auto_pop(error) #看下这个代码内部实现:response = self.full_dispatch_request() def full_dispatch_request(self): #首先执行before_first_request函数 self.try_trigger_before_first_request_functions() try: request_started.send(self) #预处理请求,在真正的请求处理之前调用,如果有返回值不会进一步请求,看代码执行也是这样的。 rv = self.preprocess_request() if rv is None: #处理请求分发,匹配url,返回视图函数的返回值,或者异常,这里没有必要是一个response对象,如果想要转化为一个对象,调用make_response rv = self.dispatch_request() except Exception as e: rv = self.handle_user_exception(e) #最后这个方法的意思,视图函数的返回值当做参数传入,返回一个response并触发后续处理函数,完成request请求。 return self.finalize_request(rv) #到此request处理分析完毕,那么ctx.auto_pop(error)就不分析了,上篇文章有介绍,详见:http://blog.csdn.net/qq_33733970/article/details/78984955 # 链接:https://blog.csdn.net/qq_33733970/java/article/details/79008831
posted on 2020-06-19 17:38 myworldworld 阅读(167) 评论(0) 收藏 举报