完善权限缓存与监控指标

This commit is contained in:
Cheng Zhou
2026-05-19 16:03:27 +08:00
parent f8a959b801
commit e95eeed90e
14 changed files with 603 additions and 335 deletions
+42 -20
View File
@@ -10,6 +10,35 @@ from app.core.api_permissions import API_ENDPOINT_PERMISSIONS, OPERATION_PREREQU
from app.core.permission_cache import get_permission_cache
async def _get_project_permission_overrides(
db: AsyncSession,
study_id: uuid.UUID,
) -> dict[str, dict[str, bool]]:
cache = get_permission_cache()
cached_permissions = cache.get_project_permissions(study_id)
from app.core.permission_monitor import get_permission_monitor
monitor = get_permission_monitor()
if cached_permissions is not None:
monitor.record_cache_hit()
return cached_permissions
monitor.record_cache_miss()
result = await db.execute(
select(ApiEndpointPermission).where(
ApiEndpointPermission.study_id == study_id,
)
)
rows = result.scalars().all()
permissions: dict[str, dict[str, bool]] = {}
for row in rows:
permissions.setdefault(row.role, {})[row.endpoint_key] = row.allowed
cache.set_project_permissions(study_id, permissions)
return permissions
async def role_has_api_permission(
db: AsyncSession,
study_id: uuid.UUID,
@@ -21,18 +50,12 @@ async def role_has_api_permission(
if role == "ADMIN":
return True
result = await db.execute(
select(ApiEndpointPermission).where(
ApiEndpointPermission.study_id == study_id,
ApiEndpointPermission.role == role,
ApiEndpointPermission.endpoint_key == endpoint_key,
)
)
perm = result.scalar_one_or_none()
if perm is None:
permissions = await _get_project_permission_overrides(db, study_id)
allowed = permissions.get(role or "", {}).get(endpoint_key)
if allowed is None:
return False
if not perm.allowed:
if not allowed:
return False
if check_prerequisites:
@@ -77,12 +100,7 @@ async def get_api_endpoint_permissions(
返回格式: {role: {endpoint_key: {allowed: bool}}}
"""
result = await db.execute(
select(ApiEndpointPermission).where(
ApiEndpointPermission.study_id == study_id,
)
)
rows = result.scalars().all()
overrides = await _get_project_permission_overrides(db, study_id)
roles = ["PM", "CRA", "PV", "MEDICAL_REVIEW", "IMP", "QA"]
matrix: dict[str, dict[str, dict[str, bool]]] = {}
@@ -92,10 +110,11 @@ async def get_api_endpoint_permissions(
default_allowed = role in config.get("default_roles", [])
matrix[role][endpoint_key] = {"allowed": default_allowed}
for row in rows:
if row.role not in matrix:
matrix[row.role] = {}
matrix[row.role][row.endpoint_key] = {"allowed": row.allowed}
for role, endpoints in overrides.items():
if role not in matrix:
matrix[role] = {}
for endpoint_key, allowed in endpoints.items():
matrix[role][endpoint_key] = {"allowed": allowed}
return matrix
@@ -132,5 +151,8 @@ async def replace_api_endpoint_permissions(
cache = get_permission_cache()
cache.invalidate_project_permissions(study_id)
cache.invalidate_all_member_roles(study_id)
from app.core.permission_monitor import get_permission_monitor
get_permission_monitor().record_cache_invalidation()
return await get_api_endpoint_permissions(db, study_id)