關(guān)于角色權(quán)限控制,網(wǎng)上有很多參考,為了加深理解,自己就寫了一套,再對比其他的方案,學(xué)習(xí)補(bǔ)充自己的不足.
后臺需求是這樣的:
1. 系統(tǒng)擁有多個角色,每一個角色擁有若干權(quán)限,不同角色可能擁有相同權(quán)限.
2. 每一個用戶只屬于某一個角色,每一個用戶可能擁有角色外的權(quán)限.
角色:
- 管理員: 擁有其他角色的所有權(quán)限,并且能添加管理員.
- 開發(fā)組:查看操作日志,系統(tǒng)日志,發(fā)布版本更新.
開發(fā)組管理:添加開發(fā)人員.
暫且提取這么多角色吧,其他的都一樣.
解決方案:
以功能劃分權(quán)限,每一個功能是一個權(quán)限.例如:添加管理員,是一個單獨(dú)的權(quán)限,查看操作日志,是一個單獨(dú)的權(quán)限.
- 數(shù)據(jù)表:權(quán)限表,角色表,用戶表,角色-權(quán)限表,用戶-權(quán)限表;
- 權(quán)限表-用戶表多對多關(guān)系,權(quán)限表-角色表多對多關(guān)系;
- 創(chuàng)建權(quán)限表的時候,初始化所有權(quán)限,創(chuàng)建角色表的時候,初始化所有角色,并為所有角色創(chuàng)建權(quán)限;
- 在使用功能的時候,通過裝飾器去驗(yàn)證該用戶是否擁有這個功能的權(quán)限,通過則可以訪問功能,否則無法訪問.
在用戶表中創(chuàng)建權(quán)限檢測:
# 獲取用戶所屬角色與用戶個人私有權(quán)限,判斷該用戶是否用于要訪問的功能的權(quán)限.
def check_permissions(self, permission):
roles_permissions = self.admin_role.roles_permissions.all()
personal_permissions = self.admin_permissions.all()
if (permission in [role_permission.permission_value for role_permission in roles_permissions]) or (permission in [personal_permission.permission_value for personal_permission in personal_permissions]):
return True
return False
權(quán)限裝飾器中增加功能權(quán)限裝飾器:
# 用戶操作權(quán)限檢測
def permission_required(permission):
def decorator(f):
@wraps(f)
def decorated_function(*args, **kwargs):
if not current_user.check_permissions(permission):
return redirect(url_for('error.page_not_found'))
return f(*args, **kwargs)
return decorated_function
return decorator
# 添加管理員功能權(quán)限
def add_admin_required(f):
return permission_required(AdminPermissions.PermissionsValue.add_admin)(f)
- 如果用于有特殊權(quán)限,則為用戶分配特殊權(quán)限,此屬于用戶-權(quán)限關(guān)系表,不做細(xì)述.
其他代碼:
'''用戶-權(quán)限表'''
admin_to_permissions = db.Table('admin_to_permissions',
db.Column('admin_id', db.Integer, db.ForeignKey('admin.id')),
db.Column('permissions_id', db.Integer, db.ForeignKey('permissions.id')),
info={'bind_key': 'admins'}
)
'''角色-權(quán)限關(guān)系表'''
roles_to_permissions = db.Table('roles_to_permissions',
db.Column('roles_id', db.Integer, db.ForeignKey('roles.id')),
db.Column('permissions_id', db.Integer, db.ForeignKey('permissions.id')),
info={'bind_key': 'admins'}
)
# 外鍵
# 用戶外鍵關(guān)系:所屬角色之外的私有權(quán)限
admin_permissions = db.relationship('AdminPermissions', secondary=admin_to_permissions,
backref=db.backref('admins', lazy="joined"), lazy="dynamic")
# 角色外鍵關(guān)系:擁有權(quán)限關(guān)系關(guān)聯(lián)
roles_permissions = db.relationship('AdminPermissions', secondary=roles_to_permissions,
backref=db.backref('roles', lazy="joined"), lazy="dynamic")
好了,大概就說這么多吧,接下來找找自己的不足,記下以做參考.