学习随笔 Flask用户角色与权限

角色在数据库中的表示
class Permission:   # 权限常量
    FOLLOW = 0x01              # 关注用户
    COMMENT = 0x02             # 发表评论
    WRITE_ARTICLES = 0x04      # 写文章
    MODERATE_COMMENTS =0x08    # 管理他们发表的评价
    ADMINISTER = 0x80          # 管理员权限

class Role(db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    name = db.Column(db.String(64), unique=True)
    default = db.Column(db.Boolean, default=False, index=True)
    permissions = db.Column(db.Integer)
    users = db.relationship('User', backref='role')

    def __init__(self, **kwargs):   # 初始化角色权限
        super(Role, self).__init__(**kwargs)
        if self.permissions is None:
            self.permissions = 0

    @staticmethod  # # 静态方法无需实例化
    def insert_roles():
        roles = {    # 角色名对应权限
            'User' : [Permission.FOLLOW, Permission.COMMENT, Permission.WRITE_ARTICLES],
            'Moderator': [Permission.FOLLOW, Permission.COMMENT, Permission.WRITE_ARTICLES, Permission.MODERATE_COMMENTS],
            'Administrator' : [Permission.FOLLOW, Permission.COMMENT, Permission.WRITE_ARTICLES, Permission.MODERATE_COMMENTS, Permission.ADMINISTER]
        }

        default_role = 'User'
        for r in roles: # 通过角色查找现有角色去设置权限,方便修改权限和添加新角色
            role = Role.query.filter_by(name = r).first()
            if role is None: # 当数据库中没有某个角色时创建个新角色
                role = Role(name=r)
            role.reset_permissions()
            for perm in roles[r]:
                role.add_permission(perm)
            role.default = (role.name == default_role) # 判断是不是默认用户
            db.session.add(role)
        db.session.commit()

    def has_permission(self, perm): # 判断当前角色是否已经有该权限
        return self.permissions & perm == perm

    def add_permission(self, perm): # 角色添加权限
        if not self.has_permission(perm):
            self.permissions += perm

    def remove_permiss(self, perm): # 角色删除权限
        if self.has_permission(perm):
            self.permissions -= perm

    def reset_permissions(self): # 重置角色
        self.permissions = 0

    def __repr__(self):
        return '<Role %r>' % self.name

用户赋予角色和验证

class User(UserMixin, db.Model):
    __tablename__ = 'users'
    id = db.Column(db.Integer, primary_key=True)
    email = db.Column(db.String(64), unique=True, index=True)
    username = db.Column(db.String(64), unique=True, index=True)
    password_hash = db.Column(db.String(128))
    confirmed = db.Column(db.Boolean, default=False)
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))

    def __init__(self, **kwargs):  # 初始化用户角色
        super(User, self).__init__(**kwargs)
        if self.role is None:
            if self.email == current_app.config['FLASKY_ADMIN']: # 管理员用户邮箱的匹配
                self.role = Role.query.filter_by(name='Administrator').first()
            else:  # 否则都是默认用户
                self.role = Role.query.filter_by(default=True).first()

    def can(self, permissions): # 检测是否含有指定权限
        return self.role is None and (self.role.permissions & permissions) == permissions

    def is_administrator(self): # 检测是否含有所有权限,即是否是管理员
        return self.can(Permission.ADMINISTER)

class AnonymousUser(AnonymousUserMixin): # 重写匿名用户,为保持与其他用户一致性
    def can(self, permissions):
        return False

    def is_administrator(self):
        return False

login_manager.anonymous_user = AnonymousUser

检查用户权限的自定义装饰器

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)

有关于装饰器和@wraps的知识链接:https://www.cnblogs.com/Neeo/p/8371826.html

自定义装饰器的使用

@main.route('/moderate')  
@login_required  
@permission_required(Permission.MODERATE_COMMENTS)  
def moderate_test():  
    return "Just for test!"

猜你喜欢

转载自blog.csdn.net/hongchen37/article/details/80311659