Flask Vue.js全栈开发|第15章:权限管理

  • 原创
  • Madman
  • /
  • /
  • 0
  • 2614 次阅读

flask vuejs 全栈开发-min.png

Synopsis: Web 应用中并不是每个用户的权限都一样,本章我们将实现简单的 RBAC(Role-based access control) 权限控制系统,创建多个角色,每个用户属于一个角色,每个角色所拥有的权限不同。比如只有管理员角色才能访问管理后台、编辑才能发布文章

本系列的最新代码将持续更新到: http://www.madmalls.com/blog/post/latest-code/

1. 角色 Role

每个角色可以拥有多个用户,所以 RoleUser一对多关系,可以参考: http://www.madmalls.com/blog/post/post-curd-and-markdown/#12-one-to-many

1.1 定义模型

修改 back-end/app/models.py,增加:

class Permission:
    '''权限认证中的各种操作,对应二进制的位,比如
    FOLLOW: 0b00000001,转换为十六进制为 0x01
    COMMENT: 0b00000010,转换为十六进制为 0x02
    WRITE: 0b00000100,转换为十六进制为 0x04
    ...
    ADMIN: 0b10000000,转换为十六进制为 0x80

    中间还预留了第 4、5、6、7 共4位二进制位,以备后续增加操作权限
    '''
    # 关注其它用户的权限
    FOLLOW = 0x01
    # 发表评论、评论点赞与踩的权限
    COMMENT = 0x02
    # 撰写文章的权限
    WRITE = 0x04
    # 管理网站的权限(对应管理员角色)
    ADMIN = 0x80


class Role(PaginatedAPIMixin, db.Model):
    __tablename__ = 'roles'
    id = db.Column(db.Integer, primary_key=True)
    slug = db.Column(db.String(255), unique=True)
    name = db.Column(db.String(255))  # 角色名称
    default = db.Column(db.Boolean, default=False, index=True)  # 当新增用户时,是否将当前角色作为默认角色赋予新用户
    permissions = db.Column(db.Integer)  # 角色拥有的权限,各操作对应一个二进制位,能执行某项操作的角色,其位会被设为 1
    users = db.relationship('User', backref='role', lazy='dynamic')

    def __init__(self, **kwargs):
        super(Role, self).__init__(**kwargs)
        if self.permissions is None:
            self.permissions = 0

    @staticmethod
    def insert_roles():
        '''应用部署时,应该主动执行此函数,添加以下角色
        注意: 未登录的用户,可以浏览,但不能评论或点赞等
        shutup:        0b0000 0000 (0x00) 用户被关小黑屋,收回所有权限
        reader:        0b0000 0011 (0x03) 读者,可以关注别人、评论与点赞,但不能发表文章
        author:        0b0000 0111 (0x07) 作者,可以关注别人、评论与点赞,发表文章
        administrator: 0b1000 0111 (0x87) 超级管理员,拥有全部权限

        以后如果要想添加新角色,或者修改角色的权限,修改 roles 数组,再运行函数即可
        '''
        roles = {
            'shutup': ('小黑屋', ()),
            'reader': ('读者', (Permission.FOLLOW, Permission.COMMENT)),
            'author': ('作者', (Permission.FOLLOW, Permission.COMMENT, Permission.WRITE)),
            'administrator': ('管理员', (Permission.FOLLOW, Permission.COMMENT, Permission.WRITE, Permission.ADMIN)),
        }
        default_role = 'reader'
        for r in roles:  # r 是字典的键,比如 'reader'
            role = Role.query.filter_by(slug=r).first()
            if role is None:
                role = Role(slug=r, name=roles[r][0])
            role.reset_permissions()
            for perm in roles[r][1]:
                role.add_permission(perm)
            role.default = (role.slug == default_role)
            db.session.add(role)
        db.session.commit()

    def reset_permissions(self):
        self.permissions = 0

    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_permission(self, perm):
        if self.has_permission(perm):
            self.permissions -= perm

    def __str__(self):
        return self.name

    def __repr__(self):
        return '<Role {}>'.format(self.name)

类方法 insert_roles() 并不直接创建新角色对象,而是通过角色 slug 查找现有的角色,然后再进行更新。只有当数据库中没有某个角色名时才会创建新角色对象。如此一来,如果以后更新了角色列表,就可以执行更新操作了。要想添加新角色,或者修改角色的权限,修改 roles 数组,再运行函数即可

最后,让我们修改 User 模型,指定与角色的关系:

class User(PaginatedAPIMixin, db.Model):
    ...
    # 用户所属的角色
    role_id = db.Column(db.Integer, db.ForeignKey('roles.id'))
    ...

1.2 数据库迁移

修改数据模型后要使用 Flask-Migrate 进行数据库迁移:

(venv) D:\python-code\flask-vuejs-madblog\back-end>flask db migrate -m "add roles table"
(venv) D:\python-code\flask-vuejs-madblog\back-end>flask db upgrade

1.3 初始化角色表

若想把角色写入数据库,可使用 flask shell 会话,首先需要修改 back-end/madblog.py,在 shell 上下文中增加 Role

from app.models import Role
...

@app.shell_context_processor
def make_shell_context():
    return {'db': db, 'Role': Role, 'User': User, 'Post': Post, 'Comment': Comment,
            'Notification': Notification, 'Message': Message}

然后执行 flask shell 命令:

(venv) D:\python-code\flask-vuejs-madblog\back-end>flask shell
Python 3.6.1 (v3.6.1:69c0db5, Mar 21 2017, 17:54:52) [MSC v.1900 32 bit (Intel)] on win32
App: app [production]
Instance: D:\python-code\flask-vuejs-madblog\back-end\instance
>>> Role.insert_roles()
>>> Role.query.all()
[<Role 小黑屋>, <Role 读者>, <Role 作者>, <Role 管理员>]

1 roles 数据表

1.4 赋予角色

现在新注册一个用户时,会被赋予默认的角色 reader。但是,你需要想一下,如果你是第一次部署该系统时,首先会创建管理员账号,而我们在 back-end/config.py 中已经配置了 ADMINS 变量,如果用户注册时的邮箱在 ADMINS 对应的列表中,则自动将这个用户的角色提升为 administrator

注意:

因为我们创建新用户的 API 中是使用 User.from_dict(self, data, new_user=True),所以不能把自动分配用户角色的逻辑代码放到 User.__init__() 中,那样的话会先执行 __init__(),而此时 self.email 永远是 None,所以下面的代码是错误的

class User(PaginatedAPIMixin, db.Model):
    ...
    def __init__(self, **kwargs):
                                
                            
未经允许不得转载: LIFE & SHARE - 王颜公子 » Flask Vue.js全栈开发|第15章:权限管理

分享

作者

作者头像

Madman

如需 Linux / Python 相关问题付费解答,请按如下方式联系我

0 条评论

暂时还没有评论.

专题系列