在Flask中建立持久复杂对象的正确方法

时间:2014-06-04 22:39:20

标签: python flask

我正在寻找关于如何在Flask中处理持久对象的“良好实践”建议。

我有自己的类来处理用户,组,组中的用户成员资格以及用户/组权限。其中,有一个Passport类,其中包含有关当前用户及其权限的信息。

这个想法是每个用户会话应该与自己的Passport对象相关联,该对象会持久存储在视图上:这样可以在用户登录时初始化某些权限,并且可以在使用视图和执行AJAX请求时稍后进行检查。 / p>

目前我已经在Passport类中对序列进行了序列化和反序列化,以及在views.py全局作用域中初始化的FlaskPassport类,该类具有只读“passport”属性,该属性从会话变量中读取序列化的护照数据并返回反序列化的对象。并且它有一个执行相反的save()方法。此FlaskPassport类还具有用于检查权限的视图的装饰器方法。并且访问存储在序列化状态的会话中的护照数据的代码看起来非常笨拙。在更改之后必须手动保存护照对象这一事实似乎不正确 - 应该是在自动处理请求后,Flask将更改的护照对象保存到会话中。

所以,我正在寻找一些聪明的模式,可以访问所有视图都可以访问的全局护照对象,还可以让装饰器添加到需要权限检查的视图中。

1 个答案:

答案 0 :(得分:3)

有多种方法可以做到这一点,包括:

  1. passport实例存储在g上并使用before_requestafter_request处理程序对来保存/序列化会话中的实例:

    @app.before_request
    def load_passport():
        if "passport_id" in session:
            g.passport = create_passport_from_id(session["passport_id"])
    
    @app.after_request
    def serialize_passport(response):
        if hasattr(g, "passport"):
            session["passport_id"] = g.passport.id
        return response
    
  2. 使用Flask用于requestg(以及其他)的线程局部模式。在引擎盖下,它使用Werkzeug的LocalProxy,它安装在应用程序上下文或请求上下文中(取决于底层对象的生命周期):

    from flask import (_request_ctx_stack as request_ctx,
                       has_request_context, session)
    from werkzeug.local import LocalProxy
    
    current_passport = LocalProxy(get_passport)
    
    def get_passport():
        if has_request_context() and "passport_id" in session:
            if not hasattr(request_ct.top, "passport"):
                passport_id = session["passport_id"]
                request_ctx.top.passport = construct_passport_from_id(passport_id)
             return getattr(request_ctx.top, "passport", None)
        return EmptyPassport()
    
    @app.after_request
    def serialize(response):
        if current_passport.is_not_empty():
            session["passport_id"] = current_passport.id
        return response
    
  3. 值得注意的是,我选择不将整个护照序列化到会话中,因为该信息会随着每次请求来回传递(取决于您在护照中存储的信息量,这可能会也可能不会是关心你的事情。)

    值得注意的是,这些方法都不具备内在的安全性。 Flask会对会话cookie进行签名以使其防篡改,但您仍需要担心注销,新鲜度等。请查看Flask-Login's code以了解您想要考虑的其他一些事项。