feat: 权限系统重构 — 操作权限双向展开 + 启动时自动补全默认权限
## permission_service.py - init_all_menus: menu_defs 新增 inbound_purchase(采购申请) 菜单项 - init_all_menus: 创建 inbound_purchase:operation 操作元素 - 新增 ensure_default_permissions(): 启动时从 sys_user 提取活跃角色, 对空权限角色自动补全默认菜单(按角色类型分级) - 自动迁移: 已有 inbound_buy 权限的角色 → 自动获得 inbound_purchase - SUPERVISOR 启动时自动获得 inbound_purchase 菜单权限 ## decorators.py - _expand_operation_perms 改为双向桥接: 正向(inbound_buy:operation←inbound_buy:write)→通过 反向(inbound_buy←inbound_buy:operation)→通过(可编辑隐含可读) - 新增详细诊断日志,记录展开路径和失败原因 ## __init__.py - 启动时调用 PermissionService.ensure_default_permissions()
This commit is contained in:
@ -126,6 +126,44 @@ def login_required(fn):
|
||||
return fn(*args, **kwargs)
|
||||
return decorator
|
||||
|
||||
def _expand_operation_perms(permission_code, all_perms):
|
||||
"""
|
||||
操作权限自动展开映射器(双向粒度桥接)。
|
||||
"""
|
||||
if permission_code in all_perms:
|
||||
logging.info(f"[权限展开] 精确匹配: {permission_code}")
|
||||
return True
|
||||
|
||||
KNOWN_OPERATION_SUFFIXES = (
|
||||
':operation', ':add', ':edit', ':delete', ':submit',
|
||||
':approve', ':dispatch', ':write'
|
||||
)
|
||||
|
||||
if ':' in permission_code:
|
||||
prefix = permission_code.rsplit(':', 1)[0]
|
||||
else:
|
||||
prefix = permission_code
|
||||
|
||||
# 收集该模块下的所有用户权限,用于诊断日志
|
||||
module_perms = [p for p in all_perms if p.startswith(prefix)]
|
||||
|
||||
for perm in all_perms:
|
||||
if perm.startswith(prefix + ':') or perm == prefix:
|
||||
for suffix in KNOWN_OPERATION_SUFFIXES:
|
||||
if perm.endswith(suffix):
|
||||
logging.info(f"[权限展开] {permission_code} ← 用户有 {perm} → 通过")
|
||||
return True
|
||||
if ':' not in permission_code and ':' in perm:
|
||||
logging.info(f"[权限展开] {permission_code} ← 用户有 {perm}(下级权限)→ 通过")
|
||||
return True
|
||||
|
||||
logging.warning(
|
||||
f"[权限展开] 失败: 要求={permission_code}, "
|
||||
f"该模块用户权限={module_perms}, 全部权限数={len(all_perms)}"
|
||||
)
|
||||
return False
|
||||
|
||||
|
||||
def permission_required(permission_code):
|
||||
"""检查当前用户是否拥有指定权限码,同时检查用户是否仍然有效"""
|
||||
def wrapper(fn):
|
||||
@ -160,8 +198,13 @@ def permission_required(permission_code):
|
||||
return jsonify(msg='权限查询失败'), 403
|
||||
|
||||
all_perms = perm_dict.get('menus', []) + perm_dict.get('elements', [])
|
||||
if permission_code not in all_perms:
|
||||
logging.warning(f"权限检查失败: 角色={user_role}, 所需权限={permission_code}")
|
||||
|
||||
# ★ 操作权限展开检查(粒度桥接)
|
||||
if not _expand_operation_perms(permission_code, all_perms):
|
||||
logging.warning(
|
||||
f"权限检查失败: 角色={user_role}, 所需={permission_code}, "
|
||||
f"拥有={[p for p in all_perms if permission_code.split(':')[0] in p]}"
|
||||
)
|
||||
return jsonify(msg='权限不足:您没有访问此资源的权限'), 403
|
||||
return fn(*args, **kwargs)
|
||||
return decorator
|
||||
|
||||
Reference in New Issue
Block a user