【问题标题】:Use database to store session instead of Cookie with Flask使用数据库存储会话而不是使用 Flask 的 Cookie
【发布时间】:2015-07-08 18:11:13
【问题描述】:

我有一个带有 Flask 的 python 项目。

我正在使用 SQL Alchemy(根据文档的此页面:http://flask.pocoo.org/docs/0.10/patterns/sqlalche)来处理我的数据库操作。

我正在使用Flask.session 来存储用户信息(身份验证状态、偏好等)

默认 Flask 的 Session 行为是将会话存储在用户的 cookie 中,并用secret_key 对这个 cookie 进行签名,这样用户就无法更改它,但他们可以读取它。

我不喜欢我的用户能够“看到”会话的内容。 Flask 是否提供了一种将会话内容存储在 ORM (SQLAlchemy) 中的内置方式,还是我必须自己实现?

谢谢!

【问题讨论】:

    标签: python session flask sqlalchemy


    【解决方案1】:

    本文改编自http://flask.pocoo.org/snippets/75/

    如果您需要存储大量会话数据,将数据从 cookie 移动到服务器是有意义的。在这种情况下,您可能希望使用 redis 作为实际会话数据的存储后端。

    以下代码使用 redis 实现会话后端。它允许您传入一个 redis 客户端或连接到本地主机上的 redis 实例。所有的键都带有一个指定的前缀,默认为 session:。

    import pickle
    from datetime import timedelta
    from uuid import uuid4
    from redis import Redis
    from werkzeug.datastructures import CallbackDict
    from flask.sessions import SessionInterface, SessionMixin
    
    
    class RedisSession(CallbackDict, SessionMixin):
    
        def __init__(self, initial=None, sid=None, new=False):
            def on_update(self):
                self.modified = True
            CallbackDict.__init__(self, initial, on_update)
            self.sid = sid
            self.new = new
            self.modified = False
    
    
    class RedisSessionInterface(SessionInterface):
        serializer = pickle
        session_class = RedisSession
    
        def __init__(self, redis=None, prefix='session:'):
            if redis is None:
                redis = Redis()
            self.redis = redis
            self.prefix = prefix
    
        def generate_sid(self):
            return str(uuid4())
    
        def get_redis_expiration_time(self, app, session):
            if session.permanent:
                return app.permanent_session_lifetime
            return timedelta(days=1)
    
        def open_session(self, app, request):
            sid = request.cookies.get(app.session_cookie_name)
            if not sid:
                sid = self.generate_sid()
                return self.session_class(sid=sid, new=True)
            val = self.redis.get(self.prefix + sid)
            if val is not None:
                data = self.serializer.loads(val)
                return self.session_class(data, sid=sid)
            return self.session_class(sid=sid, new=True)
    
        def save_session(self, app, session, response):
            domain = self.get_cookie_domain(app)
            if not session:
                self.redis.delete(self.prefix + session.sid)
                if session.modified:
                    response.delete_cookie(app.session_cookie_name,
                                           domain=domain)
                return
            redis_exp = self.get_redis_expiration_time(app, session)
            cookie_exp = self.get_expiration_time(app, session)
            val = self.serializer.dumps(dict(session))
            self.redis.setex(self.prefix + session.sid, val,
                             int(redis_exp.total_seconds()))
            response.set_cookie(app.session_cookie_name, session.sid,
                                expires=cookie_exp, httponly=True,
                                domain=domain)
    

    以下是启用它的方法:

    app = Flask(__name__)
    app.session_interface = RedisSessionInterface()
    

    如果您收到 total_seconds 缺失的属性错误,则表示您使用的 Python 版本早于 2.7。在这种情况下,您可以使用此函数来替代 total_seconds 方法:

    def total_seconds(td):
        return td.days * 60 * 60 * 24 + td.seconds
    

    【讨论】:

    • 我看到了 sn-ps,但它并没有完全回答我的问题。我不想使用其他数据存储。我想使用我正在用于我的模型的那个。我知道我会有一些性能问题。但它更方便。 (这就是 PHP 中使用的,会话由 mysql 处理(在大多数情况下))
    猜你喜欢
    • 1970-01-01
    • 2013-07-15
    • 2021-02-20
    • 2016-09-01
    • 1970-01-01
    • 2017-01-10
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多