Files
ai-agent-admin/backend-fastapi/app/field_permission_cache.py
T
2026-06-08 18:14:59 +08:00

226 lines
6.2 KiB
Python

"""
字段权限缓存管理
使用 Redis 缓存字段权限配置,提高查询性能
"""
from typing import Dict, List, Optional
import json
from sqlalchemy.ext.asyncio import AsyncSession
from utils.redis import RedisClient
class FieldPermissionCache:
"""字段权限缓存管理器"""
# 缓存键前缀
CACHE_PREFIX = "field_perm"
# 缓存过期时间(秒)
CACHE_TTL = 3600 # 1小时
@classmethod
def _get_cache_key(cls, role_id: str, resource_type: str) -> str:
"""生成缓存键"""
return f"{cls.CACHE_PREFIX}:{role_id}:{resource_type}"
@classmethod
def _get_roles_cache_key(cls, role_ids: List[str], resource_type: str) -> str:
"""生成多角色缓存键"""
sorted_role_ids = sorted(role_ids)
roles_str = "_".join(sorted_role_ids)
return f"{cls.CACHE_PREFIX}:roles:{roles_str}:{resource_type}"
@classmethod
async def get(
cls,
role_id: str,
resource_type: str
) -> Optional[List[Dict]]:
"""
从缓存获取字段权限配置
:param role_id: 角色ID
:param resource_type: 资源类型
:return: 字段权限配置列表,如果不存在返回 None
"""
try:
redis_client = await RedisClient.get_client()
except Exception:
return None
cache_key = cls._get_cache_key(role_id, resource_type)
cached_data = await redis_client.get(cache_key)
if cached_data:
try:
return json.loads(cached_data)
except json.JSONDecodeError:
return None
return None
@classmethod
async def set(
cls,
role_id: str,
resource_type: str,
configs: List[Dict]
) -> None:
"""
设置字段权限配置到缓存
:param role_id: 角色ID
:param resource_type: 资源类型
:param configs: 字段权限配置列表
"""
try:
redis_client = await RedisClient.get_client()
except Exception:
return
cache_key = cls._get_cache_key(role_id, resource_type)
cache_data = json.dumps(configs, ensure_ascii=False)
await redis_client.setex(
cache_key,
cls.CACHE_TTL,
cache_data
)
@classmethod
async def get_merged(
cls,
role_ids: List[str],
resource_type: str
) -> Optional[Dict[str, Dict]]:
"""
从缓存获取合并后的字段权限配置
:param role_ids: 角色ID列表
:param resource_type: 资源类型
:return: 合并后的字段权限配置字典
"""
try:
redis_client = await RedisClient.get_client()
except Exception:
return None
cache_key = cls._get_roles_cache_key(role_ids, resource_type)
cached_data = await redis_client.get(cache_key)
if cached_data:
try:
return json.loads(cached_data)
except json.JSONDecodeError:
return None
return None
@classmethod
async def set_merged(
cls,
role_ids: List[str],
resource_type: str,
merged_config: Dict[str, Dict]
) -> None:
"""
设置合并后的字段权限配置到缓存
:param role_ids: 角色ID列表
:param resource_type: 资源类型
:param merged_config: 合并后的字段权限配置
"""
try:
redis_client = await RedisClient.get_client()
except Exception:
return
cache_key = cls._get_roles_cache_key(role_ids, resource_type)
cache_data = json.dumps(merged_config, ensure_ascii=False)
await redis_client.setex(
cache_key,
cls.CACHE_TTL,
cache_data
)
@classmethod
async def delete(
cls,
role_id: str,
resource_type: str
) -> None:
"""
删除指定角色和资源类型的缓存
:param role_id: 角色ID
:param resource_type: 资源类型
"""
try:
redis_client = await RedisClient.get_client()
except Exception:
return
cache_key = cls._get_cache_key(role_id, resource_type)
await redis_client.delete(cache_key)
@classmethod
async def delete_by_role(cls, role_id: str) -> None:
"""
删除指定角色的所有字段权限缓存
:param role_id: 角色ID
"""
try:
redis_client = await RedisClient.get_client()
except Exception:
return
# 删除该角色的所有缓存
pattern = f"{cls.CACHE_PREFIX}:{role_id}:*"
keys = await redis_client.keys(pattern)
if keys:
await redis_client.delete(*keys)
# 删除包含该角色的多角色缓存
pattern = f"{cls.CACHE_PREFIX}:roles:*"
keys = await redis_client.keys(pattern)
for key in keys:
if role_id in key:
await redis_client.delete(key)
@classmethod
async def delete_by_resource(cls, resource_type: str) -> None:
"""
删除指定资源类型的所有字段权限缓存
:param resource_type: 资源类型
"""
try:
redis_client = await RedisClient.get_client()
except Exception:
return
# 删除该资源类型的所有缓存
pattern = f"{cls.CACHE_PREFIX}:*:{resource_type}"
keys = await redis_client.keys(pattern)
if keys:
await redis_client.delete(*keys)
@classmethod
async def clear_all(cls) -> None:
"""清除所有字段权限缓存"""
try:
redis_client = await RedisClient.get_client()
except Exception:
return
pattern = f"{cls.CACHE_PREFIX}:*"
keys = await redis_client.keys(pattern)
if keys:
await redis_client.delete(*keys)