23

我正在编写一个应用程序,该应用程序具有多个充当用户的类(例如,学校帐户和员工帐户)。我正在尝试使用 Flask-Login 来简化此操作,但我不太确定如何实现,这样当用户登录时,我可以让我的应用程序检查用户名是否属于学校帐户或员工帐户,然后正确登录。

我知道如何确定它属于哪种类型的帐户(因为所有用户名都必须是唯一的)。但在那之后,我不确定如何告诉应用程序我希望它登录该特定用户。

现在,我只有一个通用登录页面。如果我为员工帐户和学校帐户创建单独的登录页面会更容易吗?我通过 Flask-SQLAlchemy 使用 MySQL 数据库。

4

6 回答 6

49

您可以为每个用户定义一个特定的角色。例如,用户“x”可以是 SCHOOL,而用户“y”可以是“STAFF”。

class User(db.Model):

    __tablename__ = 'User'
    id = db.Column(db.Integer,primary_key=True)
    username = db.Column(db.String(80),unique=True)
    pwd_hash = db.Column(db.String(200))
    email = db.Column(db.String(256),unique=True)
    is_active = db.Column(db.Boolean,default=False)
    urole = db.Column(db.String(80))


    def __init__(self,username,pwd_hash,email,is_active,urole):
            self.username = username
            self.pwd_hash = pwd_hash
            self.email = email
            self.is_active = is_active
            self.urole = urole

    def get_id(self):
            return self.id
    def is_active(self):
            return self.is_active
    def activate_user(self):
            self.is_active = True         
    def get_username(self):
            return self.username
    def get_urole(self):
            return self.urole

然而,Flask-login 还没有用户角色的概念,我编写了自己的 login_required 装饰器版本来覆盖它。所以你可能想使用类似的东西:

def login_required(role="ANY"):
    def wrapper(fn):
        @wraps(fn)
        def decorated_view(*args, **kwargs):

            if not current_user.is_authenticated():
               return current_app.login_manager.unauthorized()
            urole = current_app.login_manager.reload_user().get_urole()
            if ( (urole != role) and (role != "ANY")):
                return current_app.login_manager.unauthorized()      
            return fn(*args, **kwargs)
        return decorated_view
    return wrapper

然后,您可以在视图函数上使用此装饰器,例如:

@app.route('/school/')
@login_required(role="SCHOOL")
def restricted_view_for_school():
    pass
于 2013-04-08T16:59:50.360 回答
12

@codegeek 我发现这非常有用,谢谢。我不得不稍微修改一下代码才能让它为我工作,所以我想我会把它放在这里以防它可以帮助其他人:

from functools import wraps

login_manager = LoginManager()

...

def login_required(role="ANY"):
    def wrapper(fn):
        @wraps(fn)
        def decorated_view(*args, **kwargs):
            if not current_user.is_authenticated():
              return login_manager.unauthorized()
            if ((current_user.role != role) and (role != "ANY")):
                return login_manager.unauthorized()
            return fn(*args, **kwargs)
        return decorated_view
    return wrapper
于 2014-03-14T20:14:05.873 回答
5

这是你可以做的一个例子。我没有使用 Flask-SQLAlchemy 的经​​验,但应该不会有太大的不同。下面的示例直接使用 SQLAlchemy。

首先,您定义一个继承自的用户类,Base以便它可以被 ORM(声明性)映射

class User(Base):

    __tablename__ = 'user_table'
    id = Column(Integer, primary_key=True)
    email = Column(String(45), unique=True)
    name = Column(String(45))
    pwd = Column(String(8))
    user_role = Column(String(15))

    __mapper_args__ = {
        'polymorphic_identity': 'user_table',
        'polymorphic_on': user_role
    }

一旦你的父类类准备好,为你想要的每个角色设置一个不同的类。

class SchoolAccount(User):
    __tablename__ = 'school_account'
    id = Column(Integer, ForeignKey('user_table.id'), primary_key=True)
    representative_name = Column(String(45))

    __mapper_args__ = {
        'polymorphic_identity': 'school_account'
    } 

使用 Flask-Login 登录用户并根据角色限制访问。

这是具有两个不同角色的登录系统的示例。这是烧瓶、烧瓶-sqlalchemy、烧瓶登录的一个很好的教程:http: //blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins

于 2013-04-08T14:37:03.860 回答
3

看看Flask-Security中的“角色管理” 。它可以很容易地与 Flask-Login 集成。

于 2015-07-29T17:02:21.170 回答
3

一个选项是@lv10 回答中提到的Flask User 。它实现了对 User 的抽象来处理很多事情,其中​​之一是基于角色的身份验证

代码将与@codegeek 答案中的代码基本相同,但 User 类上的“urole”属性应重命名为“roles”,并且角色必须是具有“name”属性的类(您可以从文档中复制粘贴)。您不需要定义 login_required,因为它已经实现为 roles_required。所以,而不是@login_required(role='rolename')我们有@roles_required('rolename').

出于安全原因,我刚开始使用此 API,这是一次很棒的体验。我强烈推荐给在密码、用户身份验证和用户角色方面有问题的任何人。

于 2019-01-30T00:45:01.663 回答
0

按照接受的解决方案(由@codegeek),如果您希望针对每个路由标记多个角色,并且用户具有一个/多个角色,您可以尝试以下 -

login_manager = LoginManager()


def role_required(role=[]):  
    def wrapper(fn):
        @wraps(fn)
        def decorated_view(*args, **kwargs):
            if not current_user.is_authenticated:
                return login_manager.unauthorized()

            if all(x != role1 for role1 in role for x in current_user.role) and (all(role1 != "ANY" for role1 in role)):  # One user may have multiple roles
                
                return render_template("Unauthorized_Access.html")

            return fn(*args, **kwargs)

        return decorated_view

    return wrapper

在哪里 -

虚拟用户数据库——

users = {'User_1': {'role': ['school', 'staff']}, 'User_2': {'role': ['admin']},
'User_3': {'role': ['staff', 'admin']}}

用户等级——

class User(UserMixin):
    role = None

用户加载器(重新加载用户对象的回调)

@login_manager.user_loader
def user_loader(userid):
    user = User()
    user.id = userid
    user.role = users[userid]['role']
    return user
于 2021-07-21T13:58:15.907 回答