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

时间:2013-08-12 14:47:08

标签: python flask flask-login flask-principal

我正在使用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登录知道用户已登录,但由于某种原因,current_user不一致。

我错过了某处的重要配置点吗?

2 个答案:

答案 0 :(得分:6)

我遇到了同样的问题!根本原因是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之前注册了。 Tsk tsk!这是我最终在我的引导程序中做的事情:

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提交给项目以获取文档。

答案 1 :(得分:0)

谢谢您,这是一个有用的相关观察。我一直在努力解决类似的问题,即用户角色在登录后无法持久保存在后续请求中。作为一个初学者,并与flask-user(我从没工作过)一起玩,并选择a)flask-principal和flask-login,以及b)flask-navigation而不是flask-nav。

这是这样我就可以1)容易地控制哪些菜单项出现基于具有导航标记产生的模板的外部委托和2)避免(为我总是教导要分离的逻辑和演示和写入为定制菜单渲染器如果我以后要更改HTML,那只用于更改周围HTML的flask-nav似乎并不正确。我找不到一种方法来遍历flask-nav对象或向nav项目添加自定义属性,而在flask-navigation中,我创建了一个自定义Item来扩展flask-navigation的Item以添加所需的权限。

我也试图解决为具有角色的层次结构,以防止不必把复杂的权限声明中我的观点的挑战(例如,管理员也编辑,也是用户,也是匿名用户等)已经疯狂地用Google搜索我找不到像这样的层次结构的任何概念。我也不希望在模型中为用户分配多个角色。

我的错误是:

  • 上面的加载顺序
  • 当我还没有把角色到我的模型,从而出现了许多对用户和角色之间的多对多关系,在我的无知我不知道,瓶,登录需要加载在@ login_manager.user_loader角色功能如果角色模型wheren't呢。我发出烧瓶-主信号之前代替分配login_user(用户)后在登录视图的角色。
  • 使用我的不同方法分配了角色,但在下一个请求中却忘记了。这篇文章给我的线索,我正在寻找。 这是我终于实现了 - 所有其他主要相关的代码是在文档和上述
#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其中的多个角色都分配从分配的角色下工作层次的循环。我希望其中一些可以帮助某人努力将它们联系在一起。我还有很多东西需要学习什么地方时,在不同的上下文中才能使用它们烧瓶商店的东西,。