Files
FastapiAdmin/backend/app/core/permission.py
T
zhangtao 0ce31936aa chore: 清理冗余代码与配置,优化项目结构
1.  删除无用文件与废弃代码:移除locale枚举、element-plus插件、sse路由、api token模块等
2.  简化类型导入与依赖:移除大量未使用的类型导入,统一echarts导入方式
3.  优化配置与样式:调整gitignore、样式引入顺序,新增列表动画样式
4.  修复接口与模型:修正接口返回类型、查询参数配置,更新部门模型字段
5.  优化性能与体验:添加图片懒加载,优化加载逻辑与表格渲染
6.  调整环境配置:新增并更新开发/生产环境配置文件
2026-07-23 20:49:52 +08:00

127 lines
5.0 KiB
Python

from typing import Any
from sqlalchemy import select
from sqlalchemy.ext.asyncio import AsyncSession
from sqlalchemy.sql.elements import ColumnElement
from app.core.base_schema import AuthSchema
from app.utils.common_util import get_child_id_map, get_child_recursion
class Permission:
"""为业务模型提供数据权限过滤功能"""
# 数据权限常量定义,提高代码可读性
DATA_SCOPE_SELF = 1 # 仅本人数据
DATA_SCOPE_DEPT = 2 # 本部门数据
DATA_SCOPE_DEPT_AND_CHILD = 3 # 本部门及以下数据
DATA_SCOPE_ALL = 4 # 全部数据
DATA_SCOPE_CUSTOM = 5 # 自定义数据
def __init__(self, model: Any, auth: AuthSchema, db: AsyncSession) -> None:
self.model = model
self.auth = auth
self.db = db
async def filter_query(self, query: Any) -> Any:
condition = await self._permission_condition()
return query.where(condition) if condition is not None else query
async def _permission_condition(self) -> ColumnElement | None:
if not self.auth.user or not self.auth.user.id:
return None
if self.auth.user.is_superuser:
return None
return await self._filter_by_data_scope()
async def _filter_by_data_scope(self) -> ColumnElement | None:
from sqlalchemy.orm import selectinload
from app.api.v1.module_system.role.model import RoleModel
from app.api.v1.module_system.user.model import UserModel
if not hasattr(self.model, "created_id"):
return None
stmt = select(RoleModel).options(selectinload(RoleModel.depts)).join(
RoleModel.users
).where(UserModel.id == self.auth.user.id)
result = await self.db.execute(stmt)
roles = result.scalars().all()
if not roles:
created_id_attr = getattr(self.model, "created_id", None)
if created_id_attr is not None and self.auth.user and self.auth.user.id:
return created_id_attr == self.auth.user.id
return None
data_scopes = set()
custom_dept_ids = set()
for role in roles:
data_scopes.add(role.data_scope)
if role.data_scope == self.DATA_SCOPE_CUSTOM and role.depts:
custom_dept_ids.update(dept.id for dept in role.depts)
if self.DATA_SCOPE_ALL in data_scopes:
return None
accessible_dept_ids = await self._get_accessible_dept_ids(data_scopes, custom_dept_ids)
if accessible_dept_ids:
if self.model.__name__ == "UserModel" and hasattr(self.model, "dept_id"):
dept_id_attr = getattr(self.model, "dept_id", None)
if dept_id_attr is not None:
return dept_id_attr.in_(list(accessible_dept_ids))
creator_rel = getattr(self.model, "created_by", None)
if creator_rel is not None and hasattr(UserModel, "dept_id"):
return creator_rel.has(UserModel.dept_id.in_(list(accessible_dept_ids)))
created_id_attr = getattr(self.model, "created_id", None)
if created_id_attr is not None and self.auth.user and self.auth.user.id:
return created_id_attr == self.auth.user.id
return None
if self.DATA_SCOPE_SELF in data_scopes:
if self.model.__name__ == "UserModel":
id_attr = getattr(self.model, "id", None)
if id_attr is not None and self.auth.user and self.auth.user.id:
return id_attr == self.auth.user.id
created_id_attr = getattr(self.model, "created_id", None)
if created_id_attr is not None and self.auth.user and self.auth.user.id:
return created_id_attr == self.auth.user.id
return None
created_id_attr = getattr(self.model, "created_id", None)
if created_id_attr is not None and self.auth.user and self.auth.user.id:
return created_id_attr == self.auth.user.id
return None
async def _get_accessible_dept_ids(self, data_scopes: set, custom_dept_ids: set) -> set[int]:
accessible_dept_ids = set()
user_dept_id = getattr(self.auth.user, "dept_id", None)
if self.DATA_SCOPE_CUSTOM in data_scopes:
accessible_dept_ids.update(custom_dept_ids)
if self.DATA_SCOPE_DEPT in data_scopes and user_dept_id is not None:
accessible_dept_ids.add(user_dept_id)
if self.DATA_SCOPE_DEPT_AND_CHILD in data_scopes and user_dept_id is not None:
try:
from app.api.v1.module_system.dept.model import DeptModel
dept_sql = select(DeptModel)
dept_result = await self.db.execute(dept_sql)
dept_objs = dept_result.scalars().all()
id_map = get_child_id_map(dept_objs)
dept_with_children_ids = get_child_recursion(id=user_dept_id, id_map=id_map)
accessible_dept_ids.update(dept_with_children_ids)
except Exception:
accessible_dept_ids.add(user_dept_id)
return accessible_dept_ids