添加动态权限控制
This commit is contained in:
@@ -47,10 +47,12 @@ def gen_menu(app_name, model_name, parent_menu_name, creator='admin'):
|
||||
|
||||
# 按钮权限
|
||||
buttons = [
|
||||
{"name": "Query", "title": "common.query", "auth_code": f"{app_name}:{model_lower}:query"},
|
||||
{"name": "Create", "title": "common.create", "auth_code": f"{app_name}:{model_lower}:create"},
|
||||
{"name": "Edit", "title": "common.edit", "auth_code": f"{app_name}:{model_lower}:edit"},
|
||||
{"name": "Delete", "title": "common.delete", "auth_code": f"{app_name}:{model_lower}:delete"},
|
||||
{"name": "Query", "title": "common.query", "auth_code": f"{app_name}:{model_lower}:query"},
|
||||
{"name": "Query", "title": "common.query", "auth_code": f"{app_name}:{model_lower}:import"},
|
||||
{"name": "Query", "title": "common.query", "auth_code": f"{app_name}:{model_lower}:export"},
|
||||
]
|
||||
for idx, btn in enumerate(buttons):
|
||||
btn_meta = MenuMeta.objects.create(
|
||||
|
||||
@@ -2,6 +2,7 @@ from system.models import LoginLog
|
||||
from utils.serializers import CustomModelSerializer
|
||||
from utils.custom_model_viewSet import CustomModelViewSet
|
||||
from rest_framework import serializers
|
||||
from utils.permissions import HasButtonPermission
|
||||
|
||||
class LoginLogSerializer(CustomModelSerializer):
|
||||
"""
|
||||
@@ -28,3 +29,4 @@ class LoginLogViewSet(CustomModelViewSet):
|
||||
search_fields = ['name'] # 根据实际字段调整
|
||||
ordering_fields = ['create_time', 'id']
|
||||
ordering = ['-create_time']
|
||||
permission_classes = [HasButtonPermission]
|
||||
|
||||
@@ -8,7 +8,6 @@ from django.contrib.auth.hashers import make_password
|
||||
from rest_framework.permissions import IsAuthenticated
|
||||
|
||||
from system.models import User, Menu, LoginLog
|
||||
from system.views.menu import MenuSerializer
|
||||
|
||||
from utils.serializers import CustomModelSerializer
|
||||
from utils.custom_model_viewSet import CustomModelViewSet
|
||||
@@ -79,13 +78,14 @@ class UserInfo(APIView):
|
||||
if user.is_superuser:
|
||||
roles = ['admin']
|
||||
# menus = Menu.objects.filter(pid__isnull=True).order_by('sort')
|
||||
# permissions = Menu.objects.filter(type='button').order_by('sort').values_list('auth_code', flat=True)
|
||||
permissions = Menu.objects.filter(type='button').order_by('auth_code').values_list('auth_code', flat=True)
|
||||
else:
|
||||
roles = user.get_role_name
|
||||
# menus = Menu.objects.filter(pid__isnull=True, role__users=user).order_by('sort').distinct()
|
||||
# permissions = Menu.objects.filter(type='button', role__users=user).order_by('sort').distinct().values_list('auth_code', flat=True)
|
||||
permissions = Menu.objects.filter(type='button', role__users=user).order_by('auth_code').distinct().values_list('auth_code', flat=True)
|
||||
# menus_data = MenuSerializer(menus, many=True).data
|
||||
user_data['roles'] = roles
|
||||
user_data['permissions'] = permissions
|
||||
return Response({
|
||||
"code": 0,
|
||||
"data": user_data,
|
||||
|
||||
@@ -20,6 +20,38 @@ class CustomModelViewSet(viewsets.ModelViewSet):
|
||||
# 是否支持软删除
|
||||
enable_soft_delete = False
|
||||
|
||||
def get_required_permission(self):
|
||||
# 约定:system:menu:create
|
||||
app_label = self.queryset.model._meta.app_label
|
||||
model_name = self.queryset.model._meta.model_name
|
||||
action = self.action # 'create', 'update', 'destroy', 'list', 'retrieve'
|
||||
# 只对增删改查等操作做权限控制
|
||||
action_map = {
|
||||
'create': 'create',
|
||||
'update': 'edit',
|
||||
'partial_update': 'edit',
|
||||
'destroy': 'delete',
|
||||
'list': 'query',
|
||||
'retrieve': 'query',
|
||||
}
|
||||
if action in action_map:
|
||||
perm_action = action_map[action]
|
||||
else:
|
||||
perm_action = action # 如 sync、import、export
|
||||
return f"{app_label}:{model_name}:{perm_action}"
|
||||
|
||||
def get_permissions(self):
|
||||
permissions = super().get_permissions()
|
||||
required_code = self.get_required_permission()
|
||||
if required_code:
|
||||
from utils.permissions import HasButtonPermission
|
||||
perm = HasButtonPermission()
|
||||
# 动态设置 required_permission
|
||||
perm.required_permission = required_code
|
||||
permissions.append(perm)
|
||||
return permissions
|
||||
|
||||
|
||||
def get_serializer_class(self):
|
||||
"""根据当前动作获取序列化器类"""
|
||||
return self.action_serializers.get(
|
||||
@@ -27,13 +59,6 @@ class CustomModelViewSet(viewsets.ModelViewSet):
|
||||
super().get_serializer_class()
|
||||
)
|
||||
|
||||
def get_permissions(self):
|
||||
"""根据当前动作获取权限类"""
|
||||
permissions = self.action_permissions.get(
|
||||
self.action,
|
||||
self.permission_classes
|
||||
)
|
||||
return [permission() for permission in permissions]
|
||||
|
||||
def list(self, request, *args, **kwargs):
|
||||
"""重写列表视图,支持软删除过滤"""
|
||||
|
||||
@@ -1,8 +1,48 @@
|
||||
from rest_framework import permissions
|
||||
from rest_framework.permissions import BasePermission
|
||||
from system.models import Menu
|
||||
|
||||
class IsSuperUserOrReadOnly(permissions.BasePermission):
|
||||
class IsSuperUserOrReadOnly(BasePermission):
|
||||
"""超级用户可读写,普通用户只读"""
|
||||
def has_permission(self, request, view):
|
||||
if request.method in permissions.SAFE_METHODS:
|
||||
return True
|
||||
return request.user and request.user.is_superuser
|
||||
|
||||
|
||||
|
||||
class HasButtonPermission(BasePermission):
|
||||
"""
|
||||
通用按钮权限校验
|
||||
用法:在视图中设置 required_permission = 'xxx:xxx:xxx'
|
||||
"""
|
||||
def has_permission(self, request, view):
|
||||
required_code = getattr(view, 'required_permission', None)
|
||||
if not required_code:
|
||||
# 可自动推断权限编码逻辑
|
||||
app_label = view.queryset.model._meta.app_label
|
||||
model_name = view.queryset.model._meta.model_name
|
||||
action = getattr(view, 'action', None)
|
||||
action_map = {
|
||||
'create': 'create',
|
||||
'update': 'edit',
|
||||
'partial_update': 'edit',
|
||||
'destroy': 'delete',
|
||||
'list': 'query',
|
||||
'retrieve': 'query',
|
||||
}
|
||||
if action in action_map:
|
||||
required_code = f"{app_label}:{model_name}:{action_map[action]}"
|
||||
if not required_code:
|
||||
return True # 不需要按钮权限
|
||||
user = request.user
|
||||
if not user.is_authenticated or user.is_anonymous:
|
||||
return False
|
||||
if user.is_superuser:
|
||||
return True
|
||||
role_ids = user.role.values_list('id', flat=True)
|
||||
return Menu.objects.filter(
|
||||
type='button',
|
||||
role__id__in=role_ids,
|
||||
auth_code=required_code
|
||||
).exists()
|
||||
|
||||
Reference in New Issue
Block a user