Flask Login 和 Principal - current_user 是匿名的,即使我已经登录

Posted

技术标签:

【中文标题】Flask Login 和 Principal - current_user 是匿名的,即使我已经登录【英文标题】:Flask Login and Principal - current_user is Anonymous even though I'm logged in 【发布时间】:2013-08-13 22:42:30 【问题描述】:

我正在使用 Flask Login 和 Principal 进行身份和角色管理。我的需求是直接从文档中描述的。我的代码在这里:

@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
    # Set the identity user object
    identity.user = current_user

    # Add the UserNeed to the identity
    if hasattr(current_user, 'get_id'):
        print 'current_user ' + str(current_user.get_id())
        identity.provides.add(UserNeed(current_user.get_id))

    # Assuming the User model has a list of roles, update the
    # identity with the roles that the user provides
    if hasattr(current_user, 'roles'):
        if current_user.roles:
            for role in current_user.roles:
                identity.provides.add(RoleNeed(role.name))

在我的登录代码中,我这样做:

identity_changed.send(current_app._get_current_object(),
                                  identity=Identity(user.user_id)

登录时,信号按预期触发。在随后的每次页面加载中,current_user 是匿名的并且没有用户 ID,但所有 @login_required 函数的行为就像用户已登录一样。Flask login 知道用户已登录,但由于某种原因 current_user 不一致。

我是否遗漏了某处的基本配置点?

【问题讨论】:

你在 Flask 初始化中使用 `static_url_path=''` 做任何事情吗?我遇到了类似的问题,请参阅:***.com/questions/16627384/… 这很令人困惑,因为会话和登录内容看起来还不错(用户可以登录),但在访问安全端点时我总是有一个匿名用户 【参考方案1】:

我遇到了同样的问题!根本原因是 Flask-Login 和 Flask-Principal 在请求的“预处理”阶段由 Flask 调用,按照它们在您的 Flask 应用中注册的顺序。如果你在注册 Flask-Login 之前注册了 Flask-Principal,那么 @identity_loaded.connect_via(app) 将在 @login_manager.user_loader 之前被调用,因此 current_user 将返回匿名用户。

Flask-Principal 文档示例显示了a code excerpt,其中 Flask-Principal 在 Flask-Login 之前注册。啧啧!以下是我最终在引导程序中所做的事情:

login_manager = LoginManager()
login_manager.init_app(app)

# ...

principals = Principal(app) # This must be initialized after login_manager.

然后在我的users.py查看文件中:

@identity_loaded.connect_via(app)
def on_identity_loaded(sender, identity):
    """ This function is called by Flask-Principal after a user logs in. """

    identity.user = current_user

    if isinstance(current_user, User):
        identity.provides.add(UserNeed(current_user.id))

    for permission in user.permissions:
        # Do permission-y stuff here.

这解决了我的问题。

编辑:我向项目提交了a bug report 以获取文档。

【讨论】:

【参考方案2】:

谢谢你,这是一个相关的观察,以防它有用。我一直在努力解决用户角色在登录后的后续请求中没有持续存在的类似问题。作为一个初学者,玩不同的东西,比如烧瓶用户(我从来没有工作过),并选择 a) 烧瓶主体和烧瓶登录和 b) 烧瓶导航而不是烧瓶导航。

这样我就可以 1) 根据 Principal 轻松控制显示哪些菜单项,以及 2) 避免在模板之外生成导航标记(因为我总是被教导要分离逻辑和表示,并为如果我想稍后更改 html,flask-nav 只是更改周围的 HTML 似乎不正确)。我找不到遍历烧瓶导航对象或向导航项目添加自定义属性的方法,而在烧瓶导航中,我正在创建一个自定义项目,扩展烧瓶导航的项目以添加所需的权限。

我还试图解决的挑战是有一个角色层次结构,以防止在我的视图中放置复杂的权限语句(例如,管理员也是编辑器,也是用户,也是匿名用户等)。找不到任何这样的层次结构概念。我也不想在我的模型中为一个用户分配多个角色。

我的错误是:

以上按加载顺序 由于我还没有将角色放入我的模型中,因此用户和角色之间存在多对多关系,在我的无知中,我没有意识到 Flask-Login 需要在 @login_manager.user_loader 中加载角色如果角色还没有在模型中,则起作用。我改为在 login_user(user) 之后在登录视图中分配角色,然后再发出 flask-principal 信号。 使用我的不同方法分配了角色,但在下一次请求时忘记了。这篇文章给了我正在寻找的线索。 这就是我最终要做的——所有其他与 Principal 相关的代码都与文档及以上内容相同。
#CAVEATS - still learning Flask so this may not be the right approach and it is still a W.I.P.
#added a  kind of hierarchy order field to User to drive multiple roles in Permissions
#with this model I only have to assign one role to a user

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer(), primary_key=True)
    name = db.Column(db.String(50), unique=True)
    description = db.Column(db.String(200))
    hierarchy_order = db.Column(db.Integer)
    internal = db.Column(db.Boolean) # this is only so I can identify registered users and internal users
    users = db.relationship('User', backref='role',lazy='dynamic')

    def __repr__(self):
        return '<Role: >'.format(self.name)

# changed common flask-login example @login_manager.user_loader as follows

@login_manager.user_loader
def load_user(user_id):
    user = User.query.get(int(user_id))
    #work out what roles are below current role
    permissable_roles = Role.query.filter(Role.hierarchy_order<=user.role.hierarchy_order).all()
    user.roles = permissable_roles
    return user

我非常希望将这种方法作为一种通用约定,但我认为我坚持在@login_manager.user_loader 中有一个循环,它将多个角色分配为从分配的角色向下延伸的层次结构。我希望其中的一些可以帮助那些挣扎于如何将这一切联系在一起的人。关于烧瓶存储东西的位置以及它们何时在不同的上下文中可用,我还有很多需要了解。

【讨论】:

以上是关于Flask Login 和 Principal - current_user 是匿名的,即使我已经登录的主要内容,如果未能解决你的问题,请参考以下文章

Flask-auth、Principal 和 Flask Security [关闭]

Flask-Principal 知识点

Flask-principal 教程(auth + authr)[关闭]

Flask-HttpAuth 和 Flask-Login

Flask-Login 使用和进阶

Flask-Login 和 Heroku 问题