权限管理功能的实现能够分为如下几个小块:
1,新建数据库表Role,里面包括id(Integer,主键)name(String),permission(Integer),default(boolean)。users是指向User模型的对外关系,反向赋给User模型一个role属性,这样就能够同郭User.role来访问Role模型,这样就建立了数据库之间的关系。模型里面还定义了一个静态方法(@staticmethod,能够直接经过类访问这个方法而不须要建立实例以后才能访问这个方法),它的做用是初始化Role数据表中的数据,数据库模型代码以下:html
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') @staticmethod def insert_role(): roles = { 'STAFF': (Permission.ONLY_QUERY, True), 'HIGH_STAFF': (Permission.ONLY_QUERY| Permission.FORBID, False), 'LEADER': (Permission.ONLY_QUERY| Permission.FORBID| Permission.ASSIGN, False), 'ADMINISTATOR': (0x0f, False) }#除了onlyquery以外,其余的都是模式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() def __repr__(self): return '<Role %r>' % self.name
Permission类代码以下:数据库
class Permission: ONLY_QUERY = 0x01#仅查询 FORBID = 0x03#封号 ASSIGN= 0x07#分配行号 ADMINISTRATOR = 0x0f#这个权限要异或
2,授予用户权限:在User模型中添加role的属性flask
class User(UserMixin,db.Model): __tablename__ = 'users' id = db.Column(db.SmallInteger,primary_key=True,nullable=False)#这个字段必须是id,不然没法完成登陆验证 username = db.Column(db.String(64)) password_hash = db.Column(db.String(128)) email = db.Column(db.String(64)) role_id = db.Column(db.Integer, db.ForeignKey('roles.id')) config_content = config[os.getenv('FLASK_CONFIG') or 'default']
由于User模型有role的属性,能够经过User.role来获取Role数据库中的内容,因此咱们的思路是直接经过这一特性进行操做,直接在User模型中的初始化方法中实现默认权限的赋予,是管理员给管理员权限,不是给默认的用户权限。session
def __init__(self,**kwargs): super(User,self).__init__(**kwargs) #继承了父类的初始化方法,super等价于UserMixin self.role = kwargs['role_id'] if self.role is None: if self.email == self.config_content.ADMINS: #验证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()
第4行是管理员为普通员工注册的时候提供的权限,若是是博客权限为空的用户,即刚注册的用户,能够删除第4行,如果用户冲了一个尊贵的会员就须要单独赋予权限了,因此咱们能够在User模型里建立一个修改权限的方法,须要的时候调用就能够。 app
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.ADMINISTRATOR)
3.2 将上面方法写入修饰函数中ui
#encoding:utf8 from functools import wraps from flask import abort from flask_login import current_user from app.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.ADMINISTRATOR)(f)
3.3 用修饰函数对有权限要求的路由进行修饰:url
@main.route('/forbid',methods=['GET','POST']) @login_required @permission_required(Permission.FORBID) def forbid(): return 'Hello World'
4新用户注册:spa
在view中添加以下代码:code
##注册 @main.route('/register',methods=['GET','POST']) @login_required @permission_required(Permission.ASSIGN) def register(): form = RegisterationForm() if form.validate_on_submit(): register_judge_obj = register_judge(form.permission.data) role_id = register_judge_obj.judge() user = User(username=form.username.data,password=form.password.data,email=form.email.data,role_id = role_id) db.session.add(user) db.session.commit() return redirect(url_for('main.login')) return render_template('register.html',form=form)
其中调用的register_judge类代码为
# -*- coding: utf-8 -*- from app.models import Role class register_judge: def __init__(self,permission_id): self.permission_id = permission_id def judge(self): if self.permission_id == '1': role_id = Role.query.filter_by(id=4).first() elif self.permission_id == '2': role_id = Role.query.filter_by(id=3).first() elif self.permission_id == '3': role_id = Role.query.filter_by(id=1).first() else: role_id = Role.query.filter_by(default=True).first() return role_id
实际操做过程当中遇到的坑:
1,权限存入数据库中数值改变:它实际上是以2进制的方式来处理的
0b00000001 0b00000010 0b00000100 0b10000000 若是只是第一个权限,它的值为1 若是是第二个权限(0b00000001|0b00000010)即0b00000011,即3 第三个(0b00000010|0b00000010|0b00000010)即0b00000111即7 以此类推 它并非以10进制来计算的
2,装饰函数的理解存在问题。