mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-21 04:46:26 +00:00
refactor(字段命名): 统一将created_at和updated_at重命名为created_time和updated_time
重构字段命名以保持一致性,将时间相关字段从created_at/updated_at统一改为created_time/updated_time 同时调整相关查询参数、服务层映射和模板文件中的字段命名 优化权限过滤逻辑,提取为独立的Permission类
This commit is contained in:
@@ -9,14 +9,10 @@ from sqlalchemy import asc, func, select, delete, Select, desc, update, or_, and
|
||||
from sqlalchemy import inspect as sa_inspect
|
||||
|
||||
from app.core.base_model import MappedBase
|
||||
from app.utils.common_util import get_child_id_map, get_child_recursion
|
||||
from app.core.exceptions import CustomException
|
||||
from app.core.permission import Permission
|
||||
from app.common.request import PageResultSchema
|
||||
from app.core.serialize import Serialize
|
||||
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.api.v1.module_system.dept.model import DeptModel
|
||||
from app.api.v1.module_system.user.model import UserModel
|
||||
|
||||
ModelType = TypeVar("ModelType", bound=MappedBase)
|
||||
CreateSchemaType = TypeVar("CreateSchemaType", bound=BaseModel)
|
||||
@@ -322,105 +318,13 @@ class CRUDBase(Generic[ModelType, CreateSchemaType, UpdateSchemaType]):
|
||||
"""
|
||||
过滤数据权限(仅用于Select)。
|
||||
"""
|
||||
perm = await self.__permission_condition()
|
||||
if perm is None:
|
||||
return sql
|
||||
return sql.where(perm)
|
||||
|
||||
async def __permission_condition(self) -> Optional[ColumnElement]:
|
||||
"""
|
||||
构造权限过滤表达式,返回None表示不限制。
|
||||
"""
|
||||
# 如果不需要检查数据权限,则不限制
|
||||
if not self.current_user or not self.auth.check_data_scope:
|
||||
return None
|
||||
|
||||
# 如果模型没有创建人created_id字段,则不限制
|
||||
if not hasattr(self.model, "created_id"):
|
||||
return None
|
||||
|
||||
# 超级管理员可以查看所有数据
|
||||
if getattr(self.current_user, "is_superuser", False):
|
||||
return None
|
||||
|
||||
# 如果用户没有部门或角色,则只能查看自己的数据
|
||||
if not getattr(self.current_user, "dept_id", None) or not getattr(self.current_user, "roles", None):
|
||||
created_id_attr = getattr(self.model, "created_id", None)
|
||||
if created_id_attr is not None:
|
||||
return created_id_attr == self.current_user.id
|
||||
return None
|
||||
|
||||
# 获取用户所有角色的权限范围
|
||||
data_scopes = set()
|
||||
dept_ids = set()
|
||||
roles = getattr(self.current_user, "roles", []) or []
|
||||
|
||||
for role in roles:
|
||||
# 角色的部门集合
|
||||
if hasattr(role, 'depts') and role.depts:
|
||||
for dept in role.depts:
|
||||
dept_ids.add(dept.id)
|
||||
data_scopes.add(role.data_scope)
|
||||
|
||||
# 如果有全部数据权限,直接返回
|
||||
if 4 in data_scopes:
|
||||
# 全部数据权限
|
||||
return None
|
||||
|
||||
# 如果有自定义数据权限且部门ID存在,优先处理
|
||||
if 5 in data_scopes and dept_ids:
|
||||
# 自定义数据权限
|
||||
creator_rel = getattr(self.model, "creator", None)
|
||||
if hasattr(UserModel, 'dept_id') and creator_rel is not None:
|
||||
return creator_rel.has(getattr(UserModel, 'dept_id').in_(list(dept_ids)))
|
||||
else:
|
||||
created_id_attr = getattr(self.model, "created_id", None)
|
||||
if created_id_attr is not None:
|
||||
return created_id_attr == self.current_user.id
|
||||
return None
|
||||
|
||||
# 处理其他数据权限范围
|
||||
dept_id_val = getattr(self.current_user, "dept_id", None)
|
||||
|
||||
if 1 in data_scopes:
|
||||
# 仅本人数据
|
||||
created_id_attr = getattr(self.model, "created_id", None)
|
||||
if created_id_attr is not None:
|
||||
return created_id_attr == self.current_user.id
|
||||
return None
|
||||
|
||||
if 2 in data_scopes and dept_id_val is not None:
|
||||
# 本部门数据
|
||||
dept_ids.add(dept_id_val)
|
||||
|
||||
if 3 in data_scopes and dept_id_val is not None:
|
||||
# 本部门及以下数据(查询所有部门并递归)
|
||||
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_child_ids = get_child_recursion(id=dept_id_val, id_map=id_map)
|
||||
dept_ids.add(dept_id_val) # 包含本部门
|
||||
for child_id in dept_child_ids:
|
||||
dept_ids.add(child_id)
|
||||
|
||||
# 处理2、3汇总的数据权限
|
||||
if (2 in data_scopes or 3 in data_scopes) and dept_ids:
|
||||
# 使用关系creator进行筛选(若存在),否则回退到仅本人数据
|
||||
creator_rel = getattr(self.model, "creator", None)
|
||||
if hasattr(UserModel, 'dept_id') and creator_rel is not None and dept_ids:
|
||||
return creator_rel.has(getattr(UserModel, 'dept_id').in_(list(dept_ids)))
|
||||
else:
|
||||
created_id_attr = getattr(self.model, "created_id", None)
|
||||
if created_id_attr is not None:
|
||||
return created_id_attr == self.current_user.id
|
||||
return None
|
||||
|
||||
# 默认情况下,只能查看自己的数据
|
||||
created_id_attr = getattr(self.model, "created_id", None)
|
||||
if created_id_attr is not None:
|
||||
return created_id_attr == self.current_user.id
|
||||
return None
|
||||
filter = Permission(
|
||||
db=self.db,
|
||||
model=self.model,
|
||||
current_user=self.current_user,
|
||||
auth=self.auth
|
||||
)
|
||||
return await filter.filter_query(sql)
|
||||
|
||||
async def __build_conditions(self, **kwargs) -> List[ColumnElement]:
|
||||
"""
|
||||
|
||||
@@ -36,7 +36,7 @@ class PaginationQueryParam:
|
||||
self.order_by.append({field.strip(): direction.strip().lower()})
|
||||
except ValueError:
|
||||
# 如果解析失败,使用默认排序
|
||||
self.order_by = [{'updated_at': 'desc'}]
|
||||
self.order_by = [{'updated_time': 'desc'}]
|
||||
else:
|
||||
self.order_by = [{'updated_at': 'desc'}]
|
||||
self.order_by = [{'updated_time': 'desc'}]
|
||||
|
||||
|
||||
@@ -33,13 +33,17 @@ class BaseSchema(BaseModel):
|
||||
description: Optional[str] = Field(default=None, description="描述")
|
||||
created_time: Optional[DateTimeStr] = Field(default=None, description="创建时间")
|
||||
updated_time: Optional[DateTimeStr] = Field(default=None, description="更新时间")
|
||||
|
||||
class BaseCreateSchema(BaseModel):
|
||||
"""通用创建模型,包含基础字段和审计字段"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
created_id: Optional[int] = Field(default=None, description="创建人ID")
|
||||
created_by: Optional[UserInfoSchema] = Field(default=None, description="创建人信息")
|
||||
updated_id: Optional[int] = Field(default=None, description="更新人ID")
|
||||
updated_by: Optional[UserInfoSchema] = Field(default=None, description="更新人信息")
|
||||
|
||||
|
||||
class TenantSchema(BaseSchema):
|
||||
class TenantSchema(BaseModel):
|
||||
"""租户模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
@@ -47,7 +51,7 @@ class TenantSchema(BaseSchema):
|
||||
tenant: Optional[CommonSchema] = Field(default=None, description="租户信息")
|
||||
|
||||
|
||||
class CustomerSchema(BaseSchema):
|
||||
class CustomerSchema(BaseModel):
|
||||
"""客户模型"""
|
||||
model_config = ConfigDict(from_attributes=True)
|
||||
|
||||
|
||||
@@ -94,9 +94,9 @@ async def get_current_user(
|
||||
username=username,
|
||||
preload=[
|
||||
"dept",
|
||||
selectinload(UserModel.roles).selectinload(RoleModel.creator),
|
||||
selectinload(UserModel.roles).selectinload(RoleModel.created_by),
|
||||
"positions",
|
||||
"creator"
|
||||
"created_by"
|
||||
]
|
||||
)
|
||||
if not user:
|
||||
|
||||
@@ -124,7 +124,7 @@ class RequestLogMiddleware(BaseHTTPMiddleware):
|
||||
response_info = (
|
||||
f"响应状态: {response.status_code}, "
|
||||
f"响应内容长度: {content_length}, "
|
||||
f"处理时间: {process_time * 1000}ms"
|
||||
f"处理时间: {round(process_time * 1000, 3)}ms"
|
||||
)
|
||||
log.info(response_info)
|
||||
|
||||
|
||||
+244
-281
@@ -1,299 +1,262 @@
|
||||
# -*- coding: utf-8 -*-
|
||||
|
||||
from typing import TypeVar, Generic
|
||||
from sqlalchemy.orm import Session, Query
|
||||
from typing import Optional, Set, List, Dict, Any, Union, Tuple
|
||||
from sqlalchemy.sql.elements import ColumnElement
|
||||
from sqlalchemy import select, and_
|
||||
from sqlalchemy.ext.asyncio import AsyncSession
|
||||
from app.api.v1.module_system.user.model import UserModel
|
||||
from app.api.v1.module_system.dept.model import DeptModel
|
||||
from app.api.v1.module_system.role.model import RoleModel
|
||||
from app.api.v1.module_system.auth.schema import AuthSchema
|
||||
from app.utils.common_util import get_child_id_map, get_child_recursion
|
||||
|
||||
|
||||
T = TypeVar('T')
|
||||
|
||||
|
||||
class PermissionMixin(Generic[T]):
|
||||
class Permission:
|
||||
"""
|
||||
数据权限混入类
|
||||
|
||||
为业务模型提供数据权限过滤功能,支持五种权限类型:
|
||||
1. 仅本人数据权限 - 只能查看自己创建的数据
|
||||
2. 本部门数据权限 - 只能查看同部门的数据
|
||||
3. 本部门及以下数据权限 - 可以查看本部门及所有子部门的数据
|
||||
4. 全部数据权限 - 可以查看所有数据
|
||||
5. 自定义数据权限 - 通过role_dept_relation表定义可访问的部门列表
|
||||
|
||||
所有需要数据权限控制的业务模型都应该继承此混入类
|
||||
为业务模型提供数据权限过滤功能
|
||||
"""
|
||||
|
||||
@classmethod
|
||||
def get_data_permission_query(cls: type[T], db: Session, user_id: int, tenant_id: int | None = None, customer_id: int | None = None) -> Query:
|
||||
# 数据权限常量定义,提高代码可读性
|
||||
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, db: AsyncSession, model: Any, current_user: UserModel, auth: AuthSchema):
|
||||
"""
|
||||
获取数据权限过滤后的查询对象
|
||||
初始化权限过滤器实例
|
||||
|
||||
Args:
|
||||
db: 数据库会话
|
||||
user_id: 用户ID
|
||||
tenant_id: 租户ID(可选)
|
||||
customer_id: 客户ID(可选)
|
||||
model: 数据模型类
|
||||
current_user: 当前用户对象
|
||||
auth: 认证信息对象
|
||||
"""
|
||||
self.db = db
|
||||
self.model = model
|
||||
self.current_user = current_user
|
||||
self.auth = auth
|
||||
self.conditions: List[ColumnElement] = [] # 权限条件列表
|
||||
|
||||
async def get_permission_condition(self) -> Optional[ColumnElement]:
|
||||
"""
|
||||
异步构建权限过滤表达式,返回None表示不限制
|
||||
|
||||
Returns:
|
||||
权限过滤表达式或None
|
||||
"""
|
||||
# 初始化条件列表
|
||||
self.conditions = []
|
||||
|
||||
# 无用户时返回空条件
|
||||
if not self.current_user:
|
||||
return None
|
||||
|
||||
# 超级管理员跳过所有过滤
|
||||
if self.current_user.is_superuser:
|
||||
return None
|
||||
|
||||
# 租户级数据隔离
|
||||
await self._apply_tenant_isolation()
|
||||
# 客户级数据隔离
|
||||
await self._apply_customer_isolation()
|
||||
# 数据范围权限隔离
|
||||
await self._apply_data_scope_isolation()
|
||||
|
||||
# 组合所有条件
|
||||
return and_(*self.conditions) if self.conditions else None
|
||||
|
||||
async def _apply_tenant_isolation(self) -> None:
|
||||
"""
|
||||
应用租户级数据隔离
|
||||
非系统用户只能查看本租户数据
|
||||
"""
|
||||
if (hasattr(self.model, "tenant_id") and
|
||||
hasattr(self.current_user, "user_type") and
|
||||
self.current_user.user_type != 0): # 非系统用户
|
||||
|
||||
user_tenant_id = getattr(self.current_user, "tenant_id", None)
|
||||
if user_tenant_id is not None:
|
||||
self.conditions.append(getattr(self.model, "tenant_id") == user_tenant_id)
|
||||
|
||||
async def _apply_customer_isolation(self) -> None:
|
||||
"""
|
||||
应用客户级数据隔离
|
||||
客户用户只能查看自己客户的数据
|
||||
"""
|
||||
if hasattr(self.model, "customer_id"):
|
||||
user_customer_id = getattr(self.current_user, "customer_id", None)
|
||||
# 客户用户类型为2
|
||||
if (hasattr(self.current_user, "user_type") and
|
||||
self.current_user.user_type == 2 and
|
||||
user_customer_id is not None):
|
||||
|
||||
self.conditions.append(getattr(self.model, "customer_id") == user_customer_id)
|
||||
|
||||
async def _apply_data_scope_isolation(self) -> None:
|
||||
"""
|
||||
应用数据范围权限隔离
|
||||
基于角色的五种数据权限范围过滤
|
||||
支持五种权限类型:
|
||||
1. 仅本人数据权限 - 只能查看自己创建的数据
|
||||
2. 本部门数据权限 - 只能查看同部门的数据
|
||||
3. 本部门及以下数据权限 - 可以查看本部门及所有子部门的数据
|
||||
4. 全部数据权限 - 可以查看所有数据
|
||||
5. 自定义数据权限 - 通过role_dept_relation表定义可访问的部门列表
|
||||
"""
|
||||
# 只有在需要检查数据权限且模型有created_id字段时才应用数据范围过滤
|
||||
if (self.auth.check_data_scope and
|
||||
hasattr(self.model, "created_id") and
|
||||
hasattr(self.current_user, "roles")):
|
||||
|
||||
# 获取用户的权限范围和部门ID集合
|
||||
data_scopes, dept_ids = await self._get_user_data_scopes()
|
||||
|
||||
# 如果没有设置任何数据权限,默认只能查看自己的数据
|
||||
if not data_scopes:
|
||||
self._add_self_scope_condition()
|
||||
return
|
||||
|
||||
# 如果拥有全部数据权限,不需要额外过滤
|
||||
if self.DATA_SCOPE_ALL in data_scopes:
|
||||
# 但仍需处理没有部门或角色的情况
|
||||
if not getattr(self.current_user, "dept_id", None) or not self.current_user.roles:
|
||||
self._add_self_scope_condition()
|
||||
return
|
||||
|
||||
# 应用相应的数据范围过滤
|
||||
if self.DATA_SCOPE_CUSTOM in data_scopes and dept_ids:
|
||||
await self._add_custom_scope_condition(dept_ids)
|
||||
elif self.DATA_SCOPE_SELF in data_scopes:
|
||||
self._add_self_scope_condition()
|
||||
elif (self.DATA_SCOPE_DEPT in data_scopes or self.DATA_SCOPE_DEPT_AND_CHILD in data_scopes):
|
||||
await self._add_dept_scope_condition(data_scopes)
|
||||
else:
|
||||
# 默认情况下,用户只能查看自己的数据
|
||||
self._add_self_scope_condition()
|
||||
|
||||
async def _get_user_data_scopes(self) -> Tuple[Set[int], Set[int]]:
|
||||
"""
|
||||
获取用户所有角色的权限范围和部门ID集合
|
||||
|
||||
Returns:
|
||||
Tuple[Set[int], Set[int]]: (数据范围集合, 部门ID集合)
|
||||
"""
|
||||
data_scopes: Set[int] = set()
|
||||
dept_ids: Set[int] = set()
|
||||
roles = getattr(self.current_user, "roles", []) or []
|
||||
|
||||
for role in roles:
|
||||
# 获取角色关联的部门
|
||||
if hasattr(role, 'depts') and role.depts:
|
||||
for dept in role.depts:
|
||||
if hasattr(dept, 'id'):
|
||||
dept_ids.add(dept.id)
|
||||
|
||||
# 获取角色的数据范围
|
||||
if hasattr(role, 'data_scope') and role.data_scope:
|
||||
try:
|
||||
data_scopes.add(int(role.data_scope))
|
||||
except (ValueError, TypeError):
|
||||
# 数据范围格式错误,忽略此角色的数据范围
|
||||
continue
|
||||
|
||||
return data_scopes, dept_ids
|
||||
|
||||
def _add_self_scope_condition(self) -> None:
|
||||
"""
|
||||
添加仅本人数据权限条件
|
||||
"""
|
||||
if hasattr(self.model, "created_id"):
|
||||
self.conditions.append(getattr(self.model, "created_id") == self.current_user.id)
|
||||
|
||||
async def _add_custom_scope_condition(self, dept_ids: Set[int]) -> None:
|
||||
"""
|
||||
添加自定义数据权限条件
|
||||
|
||||
Args:
|
||||
dept_ids: 允许访问的部门ID集合
|
||||
"""
|
||||
creator_rel = getattr(self.model, "created_id", None)
|
||||
|
||||
if (creator_rel is not None and
|
||||
hasattr(UserModel, 'dept_id')):
|
||||
# 通过creator关系过滤部门
|
||||
self.conditions.append(
|
||||
creator_rel.has(getattr(UserModel, 'dept_id').in_(list(dept_ids)))
|
||||
)
|
||||
else:
|
||||
# 无法通过部门过滤时回退到仅本人数据
|
||||
self._add_self_scope_condition()
|
||||
|
||||
async def _add_dept_scope_condition(self, data_scopes: Set[int]) -> None:
|
||||
"""
|
||||
添加部门相关的数据权限条件
|
||||
|
||||
Args:
|
||||
data_scopes: 用户的数据权限范围集合
|
||||
"""
|
||||
dept_id_val = getattr(self.current_user, "dept_id", None)
|
||||
|
||||
# 无部门时回退到仅本人数据
|
||||
if dept_id_val is None:
|
||||
self._add_self_scope_condition()
|
||||
return
|
||||
|
||||
# 获取部门ID集合
|
||||
dept_ids = {dept_id_val} # 包含本部门
|
||||
|
||||
# 如果需要包含子部门数据
|
||||
if self.DATA_SCOPE_DEPT_AND_CHILD in data_scopes:
|
||||
child_dept_ids = await self._get_child_dept_ids(dept_id_val)
|
||||
dept_ids.update(child_dept_ids)
|
||||
|
||||
# 应用部门过滤条件
|
||||
creator_rel = getattr(self.model, "creator", None)
|
||||
|
||||
if (creator_rel is not None and
|
||||
hasattr(UserModel, 'dept_id') and
|
||||
dept_ids):
|
||||
self.conditions.append(
|
||||
creator_rel.has(getattr(UserModel, 'dept_id').in_(list(dept_ids)))
|
||||
)
|
||||
else:
|
||||
# 无法通过部门过滤时回退到仅本人数据
|
||||
self._add_self_scope_condition()
|
||||
|
||||
async def _get_child_dept_ids(self, dept_id: int) -> List[int]:
|
||||
"""
|
||||
获取指定部门的所有子部门ID
|
||||
|
||||
Args:
|
||||
dept_id: 部门ID
|
||||
|
||||
Returns:
|
||||
List[int]: 子部门ID列表
|
||||
"""
|
||||
try:
|
||||
# 查询所有部门以构建部门树
|
||||
dept_sql = select(DeptModel)
|
||||
dept_result = await self.db.execute(dept_sql)
|
||||
dept_objs = dept_result.scalars().all()
|
||||
|
||||
# 构建部门ID映射并递归获取子部门ID
|
||||
id_map = get_child_id_map(dept_objs)
|
||||
return get_child_recursion(id=dept_id, id_map=id_map)
|
||||
except Exception:
|
||||
# 异常情况下返回空列表,避免权限系统出错
|
||||
return []
|
||||
|
||||
async def filter_query(self, query: Any) -> Any:
|
||||
"""
|
||||
异步过滤查询对象
|
||||
|
||||
Args:
|
||||
query: SQLAlchemy查询对象
|
||||
|
||||
Returns:
|
||||
过滤后的查询对象
|
||||
"""
|
||||
# 获取用户信息
|
||||
user = db.query(UserModel).filter(UserModel.id == user_id).first()
|
||||
if not user:
|
||||
# 返回空查询
|
||||
return db.query(cls).filter(~cls.id.in_([]))
|
||||
|
||||
# 构建基础查询
|
||||
query = db.query(cls)
|
||||
|
||||
# 应用租户和客户数据隔离
|
||||
if hasattr(cls, 'tenant_id'):
|
||||
if tenant_id is not None:
|
||||
query = query.filter(getattr(cls, 'tenant_id') == tenant_id)
|
||||
elif user.tenant_id is not None:
|
||||
query = query.filter(getattr(cls, 'tenant_id') == user.tenant_id)
|
||||
|
||||
if hasattr(cls, 'customer_id'):
|
||||
if customer_id is not None:
|
||||
query = query.filter(getattr(cls, 'customer_id') == customer_id)
|
||||
elif user.user_type == 3 and user.customer_id is not None:
|
||||
query = query.filter(getattr(cls, 'customer_id') == user.customer_id)
|
||||
|
||||
# 获取用户的角色数据权限范围
|
||||
user_roles = db.query(RoleModel).join(UserModel.roles).filter(UserModel.id == user_id).all()
|
||||
|
||||
# 如果用户没有角色,默认只有本人权限
|
||||
if not user_roles:
|
||||
if hasattr(cls, 'created_id'):
|
||||
return query.filter(getattr(cls, 'created_id') == user_id)
|
||||
return query.filter(~cls.id.in_([]))
|
||||
|
||||
# 确定用户的数据权限范围(取最大权限)
|
||||
data_scopes = []
|
||||
for role in user_roles:
|
||||
if role.data_scope:
|
||||
data_scopes.append(role.data_scope)
|
||||
|
||||
# 构建权限过滤条件
|
||||
if '4' in data_scopes: # 全部数据权限
|
||||
return query
|
||||
elif '3' in data_scopes and hasattr(user, 'dept_id') and user.dept_id: # 本部门及以下数据权限
|
||||
return cls._filter_department_and_children(query, user.dept_id, db)
|
||||
elif '2' in data_scopes and hasattr(user, 'dept_id') and user.dept_id: # 本部门数据权限
|
||||
return cls._filter_department(query, user.dept_id, db)
|
||||
elif '5' in data_scopes: # 自定义数据权限
|
||||
return cls._filter_custom_departments(query, user_id, db)
|
||||
else: # 仅本人数据权限(默认)
|
||||
if hasattr(cls, 'created_id'):
|
||||
return query.filter(getattr(cls, 'created_id') == user_id)
|
||||
return query.filter(~cls.id.in_([]))
|
||||
|
||||
@classmethod
|
||||
def _filter_department(cls, query: Query, dept_id: Union[int, None], db: Session) -> Query:
|
||||
"""
|
||||
过滤本部门数据
|
||||
|
||||
Args:
|
||||
query: 原始查询
|
||||
dept_id: 部门ID
|
||||
db: 数据库会话
|
||||
|
||||
Returns:
|
||||
过滤后的查询
|
||||
"""
|
||||
if not dept_id:
|
||||
return query.filter(~cls.id.in_([])) # 没有部门时返回空查询
|
||||
|
||||
# 如果模型有dept_id字段,直接按部门ID过滤
|
||||
if hasattr(cls, 'dept_id'):
|
||||
return query.filter(getattr(cls, 'dept_id') == dept_id)
|
||||
|
||||
# 如果模型有created_id字段,按创建者过滤
|
||||
if hasattr(cls, 'created_id'):
|
||||
# 查询该部门的所有用户ID
|
||||
dept_user_ids = (
|
||||
db.query(UserModel.id)
|
||||
.filter(UserModel.dept_id == dept_id)
|
||||
.all()
|
||||
)
|
||||
user_ids = [user.id for user in dept_user_ids]
|
||||
if user_ids:
|
||||
return query.filter(getattr(cls, 'created_id').in_(user_ids))
|
||||
|
||||
return query.filter(~cls.id.in_([]))
|
||||
|
||||
@classmethod
|
||||
def _filter_department_and_children(cls, query: Query, dept_id: Union[int, None], db: Session) -> Query:
|
||||
"""
|
||||
过滤本部门及所有子部门数据
|
||||
|
||||
Args:
|
||||
query: 原始查询
|
||||
dept_id: 部门ID
|
||||
db: 数据库会话
|
||||
|
||||
Returns:
|
||||
过滤后的查询
|
||||
"""
|
||||
if not dept_id:
|
||||
return query.filter(~cls.id.in_([])) # 没有部门时返回空查询
|
||||
|
||||
# 递归获取所有子部门ID
|
||||
def get_all_children_dept_ids(parent_id: int) -> list[int]:
|
||||
result = [parent_id]
|
||||
children = db.query(DeptModel.id).filter(DeptModel.parent_id == parent_id).all()
|
||||
for child in children:
|
||||
result.extend(get_all_children_dept_ids(child.id))
|
||||
return result
|
||||
|
||||
all_dept_ids = get_all_children_dept_ids(dept_id)
|
||||
|
||||
# 如果模型有dept_id字段,直接按部门ID过滤
|
||||
if hasattr(cls, 'dept_id'):
|
||||
return query.filter(getattr(cls, 'dept_id').in_(all_dept_ids))
|
||||
|
||||
# 如果模型有created_id字段,按创建者过滤
|
||||
if hasattr(cls, 'created_id'):
|
||||
# 获取这些部门的所有用户ID
|
||||
dept_users = (
|
||||
db.query(UserModel.id)
|
||||
.filter(UserModel.dept_id.in_(all_dept_ids))
|
||||
.all()
|
||||
)
|
||||
user_ids = [user.id for user in dept_users]
|
||||
if user_ids:
|
||||
return query.filter(getattr(cls, 'created_id').in_(user_ids))
|
||||
|
||||
return query.filter(~cls.id.in_([]))
|
||||
|
||||
@classmethod
|
||||
def _filter_custom_departments(cls, query: Query, user_id: int, db: Session) -> Query:
|
||||
"""
|
||||
过滤自定义部门数据
|
||||
|
||||
Args:
|
||||
query: 原始查询
|
||||
user_id: 用户ID
|
||||
db: 数据库会话
|
||||
|
||||
Returns:
|
||||
过滤后的查询
|
||||
"""
|
||||
# 获取用户角色
|
||||
user_roles = db.query(RoleModel).join(UserModel.roles).filter(UserModel.id == user_id).all()
|
||||
|
||||
# 收集所有可访问的部门ID
|
||||
accessible_dept_ids: set[int] = set()
|
||||
for role in user_roles:
|
||||
if role.data_scope == '5' and role.depts:
|
||||
accessible_dept_ids.update([dept.id for dept in role.depts])
|
||||
|
||||
if not accessible_dept_ids:
|
||||
# 如果没有自定义部门权限,默认返回本人权限
|
||||
if hasattr(cls, 'created_id'):
|
||||
return query.filter(getattr(cls, 'created_id') == user_id)
|
||||
return query.filter(~cls.id.in_([]))
|
||||
|
||||
# 如果模型有dept_id字段,直接按部门ID过滤
|
||||
if hasattr(cls, 'dept_id'):
|
||||
return query.filter(getattr(cls, 'dept_id').in_(accessible_dept_ids))
|
||||
|
||||
# 如果模型有created_id字段,按创建者过滤
|
||||
if hasattr(cls, 'created_id'):
|
||||
# 获取这些部门的所有用户ID
|
||||
dept_users = (
|
||||
db.query(UserModel.id)
|
||||
.filter(UserModel.dept_id.in_(accessible_dept_ids))
|
||||
.all()
|
||||
)
|
||||
user_ids = [user.id for user in dept_users]
|
||||
if user_ids:
|
||||
return query.filter(getattr(cls, 'created_id').in_(user_ids))
|
||||
|
||||
# 默认返回本人权限
|
||||
if hasattr(cls, 'created_id'):
|
||||
return query.filter(getattr(cls, 'created_id') == user_id)
|
||||
|
||||
return query.filter(~cls.id.in_([]))
|
||||
|
||||
@classmethod
|
||||
def has_permission_to_access(cls: Type[T], db: Session, user_id: int, record_id: int) -> bool:
|
||||
"""
|
||||
检查用户是否有权限访问特定记录
|
||||
|
||||
Args:
|
||||
db: 数据库会话
|
||||
user_id: 用户ID
|
||||
record_id: 记录ID
|
||||
|
||||
Returns:
|
||||
是否有权限访问
|
||||
"""
|
||||
# 获取用户信息
|
||||
user = db.query(UserModel).filter(UserModel.id == user_id).first()
|
||||
if not user:
|
||||
return False
|
||||
|
||||
# 获取记录
|
||||
record = db.query(cls).filter(cls.id == record_id).first()
|
||||
if not record:
|
||||
return False
|
||||
|
||||
# 检查租户和客户权限
|
||||
if hasattr(record, 'tenant_id') and getattr(record, 'tenant_id') is not None and hasattr(user, 'tenant_id') and user.tenant_id != getattr(record, 'tenant_id'):
|
||||
return False
|
||||
|
||||
if hasattr(record, 'customer_id') and getattr(record, 'customer_id') is not None and hasattr(user, 'customer_id') and user.customer_id != getattr(record, 'customer_id'):
|
||||
return False
|
||||
|
||||
# 获取用户角色的数据权限
|
||||
user_roles = db.query(RoleModel).join(UserModel.roles).filter(UserModel.id == user_id).all()
|
||||
data_scopes = [role.data_scope for role in user_roles if role.data_scope]
|
||||
|
||||
# 全部数据权限
|
||||
if '4' in data_scopes:
|
||||
return True
|
||||
|
||||
# 仅本人数据权限
|
||||
if hasattr(record, 'created_id') and getattr(record, 'created_id') == user_id:
|
||||
return True
|
||||
|
||||
# 部门相关权限检查
|
||||
if not hasattr(user, 'dept_id') or not user.dept_id:
|
||||
return False
|
||||
|
||||
# 本部门权限
|
||||
if '2' in data_scopes and hasattr(record, 'dept_id') and getattr(record, 'dept_id') == user.dept_id:
|
||||
return True
|
||||
|
||||
# 本部门及以下权限
|
||||
if '3' in data_scopes and hasattr(record, 'dept_id'):
|
||||
# 检查记录的部门是否在用户部门的子树中
|
||||
def is_descendant(dept_id: int, ancestor_id: int) -> bool:
|
||||
dept = db.query(DeptModel).filter(DeptModel.id == dept_id).first()
|
||||
if not dept:
|
||||
return False
|
||||
if dept.parent_id == ancestor_id:
|
||||
return True
|
||||
if dept.parent_id:
|
||||
return is_descendant(dept.parent_id, ancestor_id)
|
||||
return False
|
||||
|
||||
record_dept_id = getattr(record, 'dept_id')
|
||||
if record_dept_id:
|
||||
return is_descendant(record_dept_id, user.dept_id)
|
||||
|
||||
# 自定义数据权限
|
||||
if '5' in data_scopes and hasattr(record, 'dept_id'):
|
||||
# 收集所有可访问的部门ID
|
||||
accessible_dept_ids: set[int] = set()
|
||||
for role in user_roles:
|
||||
if role.data_scope == '5' and role.depts:
|
||||
accessible_dept_ids.update([dept.id for dept in role.depts])
|
||||
|
||||
record_dept_id = getattr(record, 'dept_id')
|
||||
if record_dept_id in accessible_dept_ids:
|
||||
return True
|
||||
|
||||
return False
|
||||
condition = await self.get_permission_condition()
|
||||
return query.where(condition) if condition is not None else query
|
||||
Reference in New Issue
Block a user