• Flask:用户角色与权限管理


    Web 应用中的用户并非都具有同等地位,为此,要为所有用户分配一个角色

    在应用中实现角色有多种方法。具体采用何种实现方法取决于所需角色的数量和细分程度。例如,简单的应用可能只需要两个角色,一个表示普通用户,一个表示管理员。对于这种情况,在 User 模型中添加一个 is_administrator 布尔值字段可能就够了。复杂的应用可能需要在普通用户和管理员之间再细分出多个不同等级的角色。有些用户可能又有多个角色,故赋予用户一系列独立的权限或许更合适。

    以下介绍的用户角色实现方式结合了分立的角色和权限,赋予用户分立的角色,但是各个角色都通过权限列表定义允许用户执行的操作。


    1、数据库中表示


    1.1 定义角色表

    class Role(db.Model):
        __tablename__ = 'roles'
        # ...
        permissions = db.Column(db.Integer, default=0)
    

    permissions字段表示角色的权限,含义如下:

    操作 权限名 权限值
    关注用户 FOLLOW 1
    在他人的文章中发表评论 COMMENT 2
    写文章 WRITE 4
    管理他人发表的评论 MODERATE 8
    管理员权限 ADMIN 16

    1.2 定义权限常量

    class Permission:
        FOLLOW = 1
        COMMENT = 2
        WRITE = 4
        MODERATE = 8
        ADMIN = 16
    

    使用 2 的幂表示权限值有个好处:每种不同的权限组合对应的值都是唯一的,方便存入角色的 permissions 字段。


    1.3 管理角色权限

    添加这些权限常量之后,可以在 Role 模型中定义几个新方法,用于管理权限:

    class Role(db.Model):
        # ...
    
        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 reset_permissions(self):
            self.permissions = 0
    
        def has_permission(self, perm):
            return self.permissions & perm == perm
    

    示例:

    >>> role = Role(name='User')
    >>> role.add_permission(Permission.WRITE)
    >>> r.has_permission(Permission.WRITE)
    True
    

    可在模型中增加静态方法,用于生成常用角色:

    class Role(db.Model):
    	# ...
    
        @staticmethod
        def insert_roles():
            roles = {
                'User': [Permission.FOLLOW, Permission.COMMENT, Permission.WRITE],
                'Moderator': [Permission.FOLLOW, Permission.COMMENT,
                Permission.WRITE, Permission.MODERATE],
                'Administrator': [Permission.FOLLOW, Permission.COMMENT,
                Permission.WRITE, Permission.MODERATE,
                Permission.ADMIN],
            }
            
            for r in roles:
            # ...
    

    2、给用户添加角色

    • 设置默认角色(生成User对象时自动配置角色信息)

      class User(UserMixin, db.Model):
          # ...
          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='User').first()
                      # ...
      
    • 生成用户后手动设置角色

      user = User(name = 'xxx')
      
      user.role = Role.query.filter_by(name='User').first()
      

    3、检测用户权限

    为了简化角色和权限的实现过程,可在 User 模型中添加一个辅助方法,检查赋予用户的角色是否有某项权限。

    from flask_login import UserMixin, AnonymousUserMixin
    
    class User(UserMixin, db.Model):
        # ...
    
        def can(self, perm):
            return self.role is not None and self.role.has_permission(perm)
    
        def is_administrator(self):
            return self.can(Permission.ADMIN)
    
    class AnonymousUser(AnonymousUserMixin):
        def can(self, permissions):
            return False
    
        def is_administrator(self):
            return False
    
    login_manager.anonymous_user = AnonymousUser
    

    如果想让视图函数只对具有特定权限的用户开放,可以使用自定义的装饰器。下面实现了两个装饰器,一个用于检查常规权限,另一个专门检查管理员权限。

    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.ADMIN)(f)
    

    使用示例:

    @main.route('/admin')
    @login_required
    @admin_required
    def for_admins_only():
        return "For administrators!"
    

    4、在模板中使用权限常量

    app/main/__init__.py:把 Permission 类加入模板上下文:

    @main.app_context_processor
    def inject_permissions():
        return dict(Permission=Permission)
    

    5、测试

    tests/test_user_model.py:添加角色和权限的单元测试

    class UserModelTestCase(unittest.TestCase):
        # ...
    
        def test_user_role(self):
            u = User(email='john@example.com', password='cat')
            self.assertTrue(u.can(Permission.FOLLOW))
            self.assertTrue(u.can(Permission.COMMENT))
            self.assertTrue(u.can(Permission.WRITE))
            self.assertFalse(u.can(Permission.MODERATE))
            self.assertFalse(u.can(Permission.ADMIN))
    
        def test_anonymous_user(self):
            u = AnonymousUser()
            self.assertFalse(u.can(Permission.FOLLOW))
            self.assertFalse(u.can(Permission.COMMENT))
            self.assertFalse(u.can(Permission.WRITE))
            self.assertFalse(u.can(Permission.MODERATE))
            self.assertFalse(u.can(Permission.ADMIN))
    
  • 相关阅读:
    Django
    索引
    idea启动tomcat后控制台日志显示中文乱码问题
    Elasticsearch
    Hive 开窗函数
    hadoop-3.1.1集群搭建
    hadoop-2.6.5集群搭建
    spark集群搭建(spark版本2.3.2)
    Zookeeper
    spark-submit(spark版本2.3.2)
  • 原文地址:https://www.cnblogs.com/yangblood/p/14585685.html
Copyright © 2020-2023  润新知