RBAC的组成
在RBAC 模型里面,有3个基础组成部分,分别是:用户、角色和权限 RBAC通过定义角色的权限,并对用户授予某个角色从而来控制用户的权限,实现了用户和权限的逻辑分类,极大地方便了权限的管理
- User(用户): 每个用户都有唯一的UID识别,并被授予不同的角色
- Role(角色):不同角色具有不同的权限
- Permission(权限):访问权限
- 用户-角色映射: 用户和角色之间的映射关系
- 角色-权限映射: 角色和权限之间的映射
RBAC权限判断实现方法
- 首先获取登录用户的所有角色
- 获取所有角色的权限
- 如果有权限就返回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'
]
}