权限管理功能的实现可以分为以下几个小块:
1,新建数据库表Role,里面包括id(Integer,主键)name(String),permission(Integer),default(boolean)。users是指向User模型的对外关系,反向赋给User模型一个role属性,这样就可以同郭User.role来访问Role模型,这样就创建了数据库之间的关系。模型里面还定义了一个静态方法(@staticmethod,可以直接通过类访问这个方法而不需要创建实例之后才能访问这个方法),它的作用是初始化Role数据表中的数据,数据库模型代码如下:
class Role(db.Model):
#定义Role的数据库模型
__tablename__ = 'roles'
id = db.Column(db.Integer, primary_key=True)
name = db.Column(db.String(64), unique=True)
permissions = db.Column(db.Integer)
default = db.Column(db.Boolean,default=False,index=True)
users = db.relationship('User', backref='role', lazy='dynamic')
def __repr__(self):
return '<Role %r>' % self.name
@staticmethod
def insert_role():
#这里需要注意的是‘|’的用法,以及python对各种进制的处理
roles = {
'User':(Permission.FOLLOW|
Permission.COMMENT|
Permission.WRITE_ARTICLES,True),
'Moderate':(Permission.FOLLOW|
Permission.COMMENT|
Permission.WRITE_ARTICLES|
Permission.MODERATE_COMMENTS,False),
'Administrator':(0xff,False)
}
for r in roles:
role = Role.query.filter_by(name=r).first()
if role is None:
role = Role(name=r)
role.permissions = roles[r][0]
role.default = roles[r][1]
db.session.add(role)
db.session.commit()
Permission类代码如下:
class Permission():
FOLLOW = 0x01
COMMENT = 0x02
WRITE_ARTICLES = 0x04
MODERATE_COMMENTS = 0x08
ADMINISTER = 0x80
2,授予用户权限:因为User模型有role的属性,可以通过User.role来获取Role数据库中的内容,所以我们的思路是直接通过这一特性进行操作,直接在User模型中的初始化方法中实现默认权限的赋予,是管理员给管理员权限,不是给默认的用户权限。
def __init__(self,**kwargs):
super(User,self).__init__(**kwargs)
#继承了父类的初始化方法,super等价于UserMixin
if self.role is None:
if self.email == current_app.config['FLASK_ADMIN']:
#验证email是否为设置的管理员的email
self.role = Role.query.filter_by(permissions=0xff).first()
if self.role is None:
#如果经过了上一步权限还为空,就给个默认的User权限
self.role = Role.query.filter_by(default=True).first()
以上只是针对于权限为空的用户,即刚注册的用户,若是用户冲了一个尊贵的会员就需要单独赋予权限了,所以我们可以在User模型里创建一个修改权限的方法,需要的时候调用就可以。
3,用它来对用户进行限制:
3.1,写一个用来判断用户权限的方法,传入用户需要的权限,进行验证,符合返回True,否则为False。这个方法在User模型里面:
def can(self,permissions):
#这个方法用来传入一个权限来核实用户是否有这个权限,返回bool值
return self.role is not None and\
(self.role.permissions & permissions) == permissions
def is_administrator(self):
#因为常用所以单独写成一个方法以方便调用,其它权限也可以这样写
return self.can(Permission.ADMINISTER)
3.2 将上面方法写入修饰函数中
#encoding:utf8
from functools import wraps
from flask import abort
from flask_login import current_user
from .models import Permission
def permission_required(permission):
def decorator(f):
@wraps(f)
def decorated_function(*args,**kwargs):
if not current_user.can(permission):
abort(403)
return f(*args, **kwargs)
return decorated_function
return decorator
def admin_required(f):
return permission_required(Permission.ADMINISTER)(f)
3.3 用修饰函数对有权限要求的路由进行修饰:
@auth.route('/admin')
@admin_required
def admin():
return '你好,老公-_-'
实际操作过程中遇到的坑:
1,权限存入数据库中数值改变:它其实是以2进制的方式来处理的
0b00000001
0b00000010
0b00000100
0b10000000
如果只是第一个权限,它的值为1
如果是第二个权限(0b00000001|0b00000010)即0b00000011,即3
第三个(0b00000010|0b00000010|0b00000010)即0b00000111即7
以此类推
它并不是以10进制来计算的
2,装饰函数的理解存在问题。