110 lines
3.9 KiB
Python
110 lines
3.9 KiB
Python
from gvsdsdk.models import User, UserRole, Role, RolePermission, Permission, UserABAC
|
||
from rest_framework.permissions import BasePermission
|
||
|
||
|
||
class IsAdminUser(BasePermission):
|
||
"""仅允许管理员(IsStaff 或 IsSuperuser)访问"""
|
||
|
||
def has_permission(self, request, view):
|
||
user = request.user
|
||
if not user or not user.is_authenticated:
|
||
return False
|
||
if not isinstance(user, User):
|
||
return False
|
||
return user.IsStaff or user.IsSuperuser
|
||
|
||
|
||
class IsCompanyMember(BasePermission):
|
||
"""验证用户当前角色属于目标数据所在公司"""
|
||
def has_object_permission(self, request, view, obj):
|
||
if not request.current_company_uuid:
|
||
return False
|
||
obj_company = getattr(obj, 'CompanyUUID_id', None) or getattr(obj, 'CompanyUUID', None)
|
||
if obj_company is None:
|
||
return True # 无公司归属的数据不做限制
|
||
return str(obj_company) == str(request.current_company_uuid)
|
||
|
||
|
||
class CompanyScopedMixin:
|
||
"""ViewSet Mixin:自动按当前角色所属公司过滤 queryset"""
|
||
company_field = 'CompanyUUID' # 可在 ViewSet 中覆盖
|
||
|
||
def get_queryset(self):
|
||
qs = super().get_queryset()
|
||
company_uuid = getattr(self.request, 'current_company_uuid', None)
|
||
if company_uuid and hasattr(qs.model, self.company_field):
|
||
qs = qs.filter(**{self.company_field: company_uuid})
|
||
return qs
|
||
|
||
def perform_create(self, serializer):
|
||
company_uuid = getattr(self.request, 'current_company_uuid', None)
|
||
if company_uuid and hasattr(serializer.Meta.model, 'CompanyUUID'):
|
||
serializer.save(CompanyUUID=company_uuid)
|
||
else:
|
||
serializer.save()
|
||
|
||
|
||
def PermissionVerifier(permission, attributes, user=None, request=None):
|
||
"""权限验证器——混合 ABAC + RBAC 检查
|
||
|
||
RBAC 仅检查当前角色(CurrentRoleUUID Cookie 指定的角色)的权限,
|
||
通过 RolePermission → Permission 链路查询。
|
||
超级管理员/员工直接放行。
|
||
"""
|
||
if not permission:
|
||
return True
|
||
if user is None:
|
||
return False
|
||
if not isinstance(user, User):
|
||
return False
|
||
|
||
# 超级管理员和员工直接放行
|
||
if user.IsSuperuser or user.IsStaff:
|
||
return True
|
||
|
||
current_role = getattr(request, 'current_role', None) if request else None
|
||
|
||
for attr in attributes:
|
||
# ABAC 检查
|
||
abac_match = UserABAC.objects.filter(
|
||
UserUUID=user.UserUUID,
|
||
HierarchicalPermissionIdentifiers=attr
|
||
).first()
|
||
if abac_match:
|
||
continue
|
||
|
||
# RBAC 检查:仅检查当前角色
|
||
if current_role and isinstance(current_role, Role):
|
||
if current_role.RoleStatus != 1:
|
||
return False
|
||
perm_uuids = RolePermission.objects.filter(
|
||
RoleUUID=current_role.RoleUUID
|
||
).values_list('PermUUID', flat=True)
|
||
rbac_result = Permission.objects.filter(
|
||
PermUUID__in=perm_uuids,
|
||
PermCode=attr,
|
||
PermStatus=1,
|
||
).exists()
|
||
else:
|
||
# 无 current_role 时回退到用户所有活跃角色
|
||
user_role_uuids = UserRole.objects.filter(
|
||
UserUUID=user.UserUUID
|
||
).values_list('RoleUUID', flat=True)
|
||
active_role_uuids = Role.objects.filter(
|
||
RoleUUID__in=user_role_uuids,
|
||
RoleStatus=1,
|
||
).values_list('RoleUUID', flat=True)
|
||
perm_uuids = RolePermission.objects.filter(
|
||
RoleUUID__in=active_role_uuids
|
||
).values_list('PermUUID', flat=True)
|
||
rbac_result = Permission.objects.filter(
|
||
PermUUID__in=perm_uuids,
|
||
PermCode=attr,
|
||
PermStatus=1,
|
||
).exists()
|
||
|
||
if rbac_result:
|
||
continue
|
||
return False
|
||
return True
|