我正在编写一个具有多个用作用户的类的应用程序(例如,学校帐户和员工帐户)。我正在尝试使用Flask-Login来实现这一点,但我不太清楚如何制作它,以便当用户登录时我可以让我的应用程序检查用户名是否属于学校帐户或员工帐户,然后适当登录。
我知道如何确定它所属的帐户类型(因为所有用户名必须是唯一的)。但在那之后,我不知道如何告诉应用程序我希望它登录该特定用户。
现在,我只有一个通用登录页面。如果我为员工帐户和学校帐户创建单独的登录页面,会更容易吗?我通过Flask-SQLAlchemy使用MySQL数据库。
答案 0 :(得分:30)
您可以使用特定角色定义每个用户。例如,用户'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
答案 1 :(得分:6)
@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
答案 2 :(得分:3)
这是你可以做的一个例子。我没有使用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登录用户并根据角色限制访问。
以下是具有两个不同角色的登录系统的示例。对于flask,flask-sqlalchemy,flask-login:http://blog.miguelgrinberg.com/post/the-flask-mega-tutorial-part-v-user-logins
,这是一个很好的教程答案 3 :(得分:1)
看看"角色管理"来自Flask-Security。它可以很容易地与Flask-Login集成。
答案 4 :(得分:0)
如@ lv10答案所述,选项为Flask User。它为处理很多事情的用户实现了一个抽象,其中之一就是Role-based authentication。
代码将基本上与@codegeek答案中的代码相同,但是User类的“ urole”属性应重命名为“ roles”,并且角色必须是具有“ name”属性的类(您可以从documentation)。您不需要定义login_required,因为已经将其定义为role_required。因此,我们有了@login_required(role='rolename')
,而不是@roles_required('rolename')
。
出于安全原因,我刚刚开始使用此API,这是非常不错的经验。我强烈建议任何密码,用户身份验证和用户角色有问题的人。
答案 5 :(得分: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