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)    收藏  举报

导航