226 lines
6.2 KiB
Python
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)
|