Django rbac 权限功能的实现

1,425 阅读2分钟
RBAC的组成

在RBAC 模型里面,有3个基础组成部分,分别是:用户、角色和权限 RBAC通过定义角色的权限,并对用户授予某个角色从而来控制用户的权限,实现了用户和权限的逻辑分类,极大地方便了权限的管理

  • User(用户): 每个用户都有唯一的UID识别,并被授予不同的角色
  • Role(角色):不同角色具有不同的权限
  • Permission(权限):访问权限
  • 用户-角色映射: 用户和角色之间的映射关系
  • 角色-权限映射: 角色和权限之间的映射 image.png
RBAC权限判断实现方法
  1. 首先获取登录用户的所有角色
  2. 获取所有角色的权限
  3. 如果有权限就返回True,没有就返回False
from django.core.cache import cache
from rest_framework.permissions import BasePermission

def get_permission_list(user):
    # 判断user是否是超级管理员
    if user.is_superuser:
        perms_list = ['admin']
    else:
        perms = Permission.objects.none()
        # 获取用户的所有的角色
        roles = user.roles.all()
        # 获取角色的所有权限
        if roles:
            for i in roles:
              perms = perms | i.perms.all()
        perms_list = perms.values_list("method", flat=True)
        perms_list = list(set(perms_list))
    cache.set(user.username + "__perms" + perms_list)
    return perms_list
        
class RbacPermission(BasePermission):
    def has_permission(self, request, view):
        # 判断用户是否登录
        if not request.user:
            perms = ['visitor'] # 没有登录就视为游客
        # 读取缓存中的权限
        perms = cache.get(user.username + "__perms" + perms_list)
        if not perms:
            perms = get_permission_list(request.user)
        if perms:
            if "admin" in perms:
                # 判断是否是超级管理员
                return True
            elif not hasattr(view, "perms_map"):
                # 判断视图对象里面是否有perms_map属性,可以通过perms_map 控制权限
                return True
            else:
                perms_map = view.perms_map
                # 获取request 的请求方法method
                _method = request._request.method.lower()
                if perms_map:
                    for key in perms_map:
                        if key == _method or key == "*":
                            if perms_map[key] in perms or perms_map[key] == "*":
                                return True
                return False
          else:
              return False
            
    def has_object_permission(self, request, view, obj):
        if not request.user:
            return False
        
变更用户角色时动态更新权限或者前端刷新
from django.db.models.signals import m2m_changed
from .models import Role, Permission, User
from django.dispatch import receiver
from django.core.cache import cache
from .permission import get_permission_list

@receiver(m2m_changed, sender=User.roles.through)
def update_perms_cache_user(sender, instance, action, **kwargs):
    if action in ['post_remove', 'post_add']:
        if cache.get(instance.username + "__perms", None):
            get_permission_list(instance)
settings.py 中使用自定义权限验证
REST_FRAMEWORK = {
'DEFAULT_PERMISSION_CLASSES': [
    'rest_framework.permissions.IsAuthenticated',
    'apps.system.permission.RbacPermission'
]
}