Files
GVSDSDK/auth/admin_service.py

156 lines
6.4 KiB
Python
Raw Permalink Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""gvsdsdk.auth.admin_service — 管理员身份统一判定服务
提供管理员身份判定的统一入口,基于两个层级的管理员权限码:
``admin:super`` —— 跨租户管理员(如 GERP 测试员),关闭租户隔离 + 公司隔离
``admin:tenant`` —— 租户内管理员(如 集团超级管理员),仅关闭公司隔离,保留租户隔离
判定顺序(适用于所有判定函数):
1. 用户未认证 → False
2. 有当前角色 → 仅依据该角色的权限码判定(角色超级管理员模式)
超级用户切换到普通角色时也应用隔离,不再因 IsSuperuser/IsStaff 直接放行
3. 无当前角色 → IsSuperuser 或 IsStaff 作为系统维护回退(仅授予 admin:tenant 级别,
不授予 admin:super,防止超级用户在未切换角色时获得跨租户越权能力)
4. 否则 → False
提供的函数:
``IsAdmin`` —— 是否为管理员(admin:super 或 admin:tenant),用于权限校验
``IsSuperAdmin`` —— 是否为跨租户管理员(仅 admin:super),用于租户隔离判定
``IsTenantAdmin``—— 是否为租户内管理员(仅 admin:tenant),用于租户内管理员判定
用法:
from gvsdsdk.auth.admin_service import IsAdmin, IsSuperAdmin
if IsAdmin(request):
... # 权限校验放行
if IsSuperAdmin(request):
... # 关闭租户隔离
"""
from __future__ import annotations
import logging as _logging
_logger = _logging.getLogger(__name__)
def _IsAuthenticated(user) -> bool:
"""兼容 gvsdsdk User(IsAuthenticated 属性)与 Django User(is_authenticated 属性)"""
if user is None:
return False
for attr in ('IsAuthenticated', 'is_authenticated'):
val = getattr(user, attr, None)
if val:
return bool(val)
return False
def _HasPerm(request=None, user=None, role_uuid=None, perm_code=None) -> bool:
"""判断当前角色是否拥有指定权限码
内部函数,供 IsAdmin / IsSuperAdmin / IsTenantAdmin 复用。
判定顺序:
1. 用户未认证 → False
2. 有当前角色 → 仅依据该角色的指定权限码判定(角色超级管理员模式)
3. 无当前角色 → IsSuperuser 或 IsStaff 作为系统维护回退(仅授予 admin:tenant 级别,
perm_code='admin:super' 时直接返回 False,防止跨租户越权)
4. 否则 → False
"""
if perm_code is None:
return False
# 1. 解析 user
if request is not None and user is None:
user = getattr(request, 'user', None)
if not _IsAuthenticated(user):
return False
# 2. 解析 role_uuid(优先从参数,其次从 request.current_role)
if role_uuid is None and request is not None:
current_role = getattr(request, 'current_role', None)
if current_role:
role_uuid = getattr(current_role, 'RoleUUID', None)
# 3. 有当前角色时,仅依据该角色的指定权限码判定(角色超级管理员模式)
if role_uuid:
try:
from gvsdsdk.models import RolePermission, Permission
perm_uuids = Permission.objects.filter(
PermCode=perm_code,
PermStatus=1,
).values_list('PermUUID', flat=True)
return RolePermission.objects.filter(
RoleUUID=role_uuid,
PermUUID__in=perm_uuids,
).exists()
except Exception:
_logger.warning('查询权限 %s 失败', perm_code, exc_info=True)
return False
# 4. 无当前角色时,IsSuperuser/IsStaff 作为系统维护回退(无角色无法做权限判定)
# 安全策略:无角色时仅授予 admin:tenant 级别权限(不授予 admin:super),
# 防止超级用户在未切换角色时获得跨租户越权能力。
# superuser 无角色 → IsAdmin=True / IsTenantAdmin=True / IsSuperAdmin=False
if perm_code == 'admin:super':
return False
return bool(getattr(user, 'IsSuperuser', False) or getattr(user, 'IsStaff', False))
def IsAdmin(request=None, user=None, role_uuid=None) -> bool:
"""判断用户是否为管理员(admin:super 或 admin:tenant)
用于权限校验:两种层级的管理员都应放行。
跨租户管理员(admin:super)和租户内管理员(admin:tenant)都是管理员。
参数:
request: 请求对象。优先从 ``request.user`` 取用户、``request.current_role`` 取角色。
user: 用户对象。``request`` 为空时使用此参数。
role_uuid: 角色 UUID(bytes 或 UUIDObj)。``request`` 为空时使用此参数;
若 ``request`` 非空则优先使用 ``request.current_role.RoleUUID``。
返回:
bool
"""
if _HasPerm(request, user, role_uuid, 'admin:super'):
return True
return _HasPerm(request, user, role_uuid, 'admin:tenant')
def IsSuperAdmin(request=None, user=None, role_uuid=None) -> bool:
"""判断用户是否为跨租户管理员(仅 admin:super)
用于隔离控制:仅 admin:super 关闭租户隔离,可跨租户查看数据。
"""
return _HasPerm(request, user, role_uuid, 'admin:super')
def IsTenantAdmin(request=None, user=None, role_uuid=None) -> bool:
"""判断用户是否为租户内管理员(仅 admin:tenant)
用于租户内管理员判定:仅关闭公司隔离,保留租户隔离。
"""
return _HasPerm(request, user, role_uuid, 'admin:tenant')
def IsCompanyAdmin(request=None, user=None, role_uuid=None) -> bool:
"""判断用户是否为公司管理员(admin:company / admin:tenant / admin:super)
公司管理员权限键 ``admin:company`` 由管理员在角色权限分配时手动勾选,
绑定到具体公司(RolePermission.CompanyUUID 维度)后,仅在该公司内生效。
继承规则(公司管理员能力):
- admin:super —— 跨租户管理员,天然具备
- admin:tenant —— 租户内管理员,自动继承(可管理租户下所有公司)
- admin:company—— 手动授予的角色,需按公司维度绑定
返回:
bool
"""
if _HasPerm(request, user, role_uuid, 'admin:company'):
return True
# 租户管理员 / 跨租户管理员自动继承公司管理员权限
if IsAdmin(request=request, user=user, role_uuid=role_uuid):
return True
return False