zoukankan      html  css  js  c++  java
  • WEB, Flask

    参考:

    https://blog.csdn.net/nunchakushuang/article/details/74652877
    http://portal.xiaoxiangzi.com/Programme/Python/7890.html
    https://www.zhihu.com/question/19786827
    http://www.woshipm.com/pd/864133.html

    1. Session是在服务端保存的一个数据结构,用来跟踪用户的状态,这个数据可以保存在集群、数据库、文件中;
    2. Cookie是客户端保存用户信息的一种机制,用来记录用户的一些信息,也是实现Session的一种方式。
    3. cookie在进行秘钥签名时要使用会话,所以要设置secret key.
    4. 设置:session['username'] = 'xxx'
    5. 删除:session.pop('username', None)
    6. session的使用方式是客户端cookie里存id,服务端session存用户数据,客户端访问服务端的时候,根据id找用户数据。

    6. 请求到来时,无论什么“数据库”的特有的session,从Cookie取出后,都是存储在Flask的Local里的ctx中的。(有关Local可以看上下文管理的第6点)从app.call__方法查看ctx.push()源码。 因为里面有session_interface,默认的是SecureCookieSessionInterface,可以自定义,例如改成app.session_interface = RedisSessionInterface(conn,key_prefix='',use_signer=False)。

    7. 请求结束时,第三方组件的session存在“数据库”中。默认的SecureCookieSessionInterface中sessionID和session的值加密后都放在Cookie中。(默认的是client-side session)

    8. Cookie有长度限制和加密后也不安全,所以session最好放在“数据库”中。(Redis是server-side session)

    1. 基本使用

    from flask import Flask, session, redirect, url_for, escape, request
    
    app = Flask(__name__)
    
    
    @app.route('/')
    def index():
        if 'username' in session:
            return 'Logged in as %s' % escape(session['username'])
        return 'You are not logged in'
    
    
    @app.route('/login', methods=['GET', 'POST'])
    def login():
        if request.method == 'POST':
            session['username'] = request.form['username']
            return redirect(url_for('index'))
        return '''
            <form action="" method="post">
                <p><input type=text name=username>
                <p><input type=submit value=Login>
            </form>
        '''
    
    
    @app.route('/logout')
    def logout():
        # remove the username from the session if it's there
        session.pop('username', None)
        return redirect(url_for('index'))
    
    
    # set the secret key.  keep this really secret:
    app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
    
    

    2. 自定义session

    pip3
    install
    Flask - Session
    
    run.py
    from flask import Flask
    from flask import session
    from pro_flask.utils.session import MySessionInterface
    
    app = Flask(__name__)
    
    app.secret_key = 'A0Zr98j/3yX R~XHH!jmN]LWX/,?RT'
    app.session_interface = MySessionInterface()
    
    
    @app.route('/login.html', methods=['GET', "POST"])
    def login():
        print(session)
        session['user1'] = 'alex'
        session['user2'] = 'alex'
        del session['user2']
    
        return "内容"
    
    
    if __name__ == '__main__':
        app.run()
    
    session.py
    # !/usr/bin/env python
    # -*- coding:utf-8 -*-
    import uuid
    import json
    from flask.sessions import SessionInterface
    from flask.sessions import SessionMixin
    from itsdangerous import Signer, BadSignature, want_bytes
    
    
    class MySession(dict, SessionMixin):
        def __init__(self, initial=None, sid=None):
            self.sid = sid
            self.initial = initial
            super(MySession, self).__init__(initial or ())
    
        def __setitem__(self, key, value):
            super(MySession, self).__setitem__(key, value)
    
        def __getitem__(self, item):
            return super(MySession, self).__getitem__(item)
    
        def __delitem__(self, key):
            super(MySession, self).__delitem__(key)
    
    
    class MySessionInterface(SessionInterface):
        session_class = MySession
        container = {}
    
        def __init__(self):
            import redis
            self.redis = redis.Redis()
    
        def _generate_sid(self):
            return str(uuid.uuid4())
    
        def _get_signer(self, app):
            if not app.secret_key:
                return None
            return Signer(app.secret_key, salt='flask-session',
                          key_derivation='hmac')
    
        def open_session(self, app, request):
            """
            程序刚启动时执行,需要返回一个session对象
            """
            sid = request.cookies.get(app.session_cookie_name)
            if not sid:
                sid = self._generate_sid()
                return self.session_class(sid=sid)
    
            signer = self._get_signer(app)
            try:
                sid_as_bytes = signer.unsign(sid)
                sid = sid_as_bytes.decode()
            except BadSignature:
                sid = self._generate_sid()
                return self.session_class(sid=sid)
    
            # session保存在redis中
            # val = self.redis.get(sid)
            # session保存在内存中
            val = self.container.get(sid)
    
            if val is not None:
                try:
                    data = json.loads(val)
                    return self.session_class(data, sid=sid)
                except:
                    return self.session_class(sid=sid)
            return self.session_class(sid=sid)
    
        def save_session(self, app, session, response):
            domain = self.get_cookie_domain(app)
            path = self.get_cookie_path(app)
            httponly = self.get_cookie_httponly(app)
            secure = self.get_cookie_secure(app)
            expires = self.get_expiration_time(app, session)
    
            val = json.dumps(dict(session))
    
            # session保存在redis中
            # self.redis.setex(name=session.sid, value=val, time=app.permanent_session_lifetime)
            # session保存在内存中
            self.container.setdefault(session.sid, val)
    
            session_id = self._get_signer(app).sign(want_bytes(session.sid))
    
            response.set_cookie(app.session_cookie_name, session_id,
                                expires=expires, httponly=httponly,
                                domain=domain, path=path, secure=secure)
    
    

    3. Flask中的session处理机制(核心)

    内置session:将session和session对应的数据保存在加密cookie中实现

    - 请求刚到来:获取SessionID(随机字符串),存在则去“数据库”(cookie(cookie就不是数据库),memcache, redis, 内存,数据库,集群,文件...)中获取原来的个人数据,否则创建一个空容器。 --> 内存:对象(SessionID:{放置数据的容器})
    	# 1. obj = 创建SecureCookieSessionInterface()
    	# 2. obj = open_session(self.request) = SecureCookieSession()
    	# self.session = SecureCookieSession()对象。 
    	self.session = self.app.open_session(self.request)
    
    
    - 处理请求,视图:操作内存中 对象(SessionID,{放置数据的容器})
    - 请求终止,响应:内存中 对象(SessionID,{放置数据的容器})
    		- 将session保存到“数据库”
    		- 把SessionID写到用户cookie中。		
    

    自定义session

    请求刚到来:
    	# 创建特殊字典,并添加到Local的ctx中。从app.__call__方法查看ctx.push()源码
    	# 调用关系:
    	#	self.session_interface.open_session(self, request)
    	# 	由于默认app中的session_interface=SecureCookieSessionInterface()
    	#		SecureCookieSessionInterface().open_session(self, request)
    	# 	自定义app中的session_interface=MySessionInterFace()
    	#		MySessionInterFace().open_session(self, request)
    	self.session = self.app.open_session(self.request)
    
    处理请求,调用:
    	session =  LocalProxy -> 偏函数 -> LocalStack -> Local -> ctx --> session
    
    请求终止,响应:
    	# 	由于默认app中的session_interface=SecureCookieSessionInterface()
    	#		SecureCookieSessionInterface().save_session(self, app, session, response)
    	# 	自定义app中的session_interface=MySessionInterFace()
    	#		MySessionInterFace().save_session(self, app, session, response)
    

    第三方session,flask_session组件,from flask_session import sessions
    请求结束时,把该session存储在Redis中,并将sessionID写进Cookie中。(看def save_session源码)

    from flask import Flask,session
    from flask_session import RedisSessionInterface
    
    app = Flask(__name__)
    app.secret_key = 'xxxxx'
    
    from redis import Redis
    conn = Redis()
    app.session_interface = RedisSessionInterface(conn,key_prefix='__',use_signer=False, permanent=False)
    
    
    @app.route('/')
    def index():
    	session['xxx'] = 123
    	return 'Index'
    
    
    if __name__ == '__main__':
    	app.run()
    

    RedisSessionInterface里与SecureCookieSessionInterface(默认的)一样有open_session,save_session方法。方法里return一个特有的session(RedisSession,看源码),请求到来时,session存在Local的ctx里。

    flask_session还有其他“数据库”,存储对应特有的session。特有的session对应的数据存储在这些“数据库”中。

    4. 问题:设置cookie时,如何设定关闭浏览器则cookie失效?

    例如在SecureCookieSessionInterface中的save_session里设置response.set_cookie('k','v',exipre=None)
    或者app.session_interface = RedisSessionInterface(conn,key_prefix='__',use_signer=False, permanent=False)
    原理都是exipre=None

  • 相关阅读:
    DEV控件GridControl常用属性设置(转)
    【649】shapely strtree STRtree 构建 RTree
    【648】计算直线间的夹角
    【646】灰度图array转为RGB三通道array
    【645】OpenCV 相关函数说明
    【644】二值图去掉面积小的部分 cv2.threshold
    Makefile中include、-include、sinclude
    openssh交叉编译
    四元数插值
    循环求余法
  • 原文地址:https://www.cnblogs.com/allen2333/p/9016003.html
Copyright © 2011-2022 走看看