使用数据库来存储会话,而不是使用Flask存储Cookie [英] Use database to store session instead of Cookie with Flask

查看:67
本文介绍了使用数据库来存储会话,而不是使用Flask存储Cookie的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我有一个Flask的python项目.

I have a python project with Flask.

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

I'm using SQL Alchemy (according to this page of the documentation : http://flask.pocoo.org/docs/0.10/patterns/sqlalche) to handle my database actions.

我正在使用 Flask.session 来存储用户信息(身份验证状态,首选项等)

I'm using Flask.session to store user's information (authentication status, preferences, ...)

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

Default Flask's Session behaviour is to store sessions in user's cookie, and to sign this cookie with secret_key so users can't alter it, but they can read it.

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

I don't like that my users are able to "see" session's content. Does Flask offer a built-in way to store session's content in ORM (SQLAlchemy), or do I have to implement that myself ?

谢谢!

推荐答案

该内容改编自 http://flask.pocoo.org/snippets/75/.

如果您需要存储大量会话数据,则可以将数据从cookie移至服务器.在这种情况下,您可能希望将redis用作实际会话数据的存储后端.

If you need to store a lot of session data it makes sense to move the data from the cookie to the server. In that case you might want to use redis as the storage backend for the actual session data.

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

The following code implements a session backend using redis. It allows you to either pass in a redis client or will connect to the redis instance on localhost. All the keys are prefixed with a specified prefix which defaults to 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方法:

If you get an attribute error that total_seconds is missing it means you're using a version of Python older than 2.7. In this case you can use this function as a replacement for the total_seconds method:

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

这篇关于使用数据库来存储会话,而不是使用Flask存储Cookie的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆