Skip to content

Commit 138ea11

Browse files
committed
update filter_data_permission
1 parent 6670c64 commit 138ea11

File tree

3 files changed

+34
-30
lines changed

3 files changed

+34
-30
lines changed

backend/app/admin/schema/data_rule.py

Lines changed: 0 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -36,7 +36,3 @@ class GetDataRuleDetail(DataRuleSchemaBase):
3636
id: int = Field(description='规则 ID')
3737
created_time: datetime = Field(description='创建时间')
3838
updated_time: datetime | None = Field(None, description='更新时间')
39-
40-
def __hash__(self) -> int:
41-
"""计算哈希值"""
42-
return hash(self.name)

backend/common/security/permission.py

Lines changed: 33 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -4,15 +4,19 @@
44

55
from fastapi import Request
66
from sqlalchemy import ColumnElement, and_, or_
7+
from sqlalchemy.ext.asyncio import AsyncSession
78

9+
from backend.app.admin.crud.crud_data_scope import data_scope_dao
810
from backend.common.enums import RoleDataRuleExpressionType, RoleDataRuleOperatorType
911
from backend.common.exception import errors
1012
from backend.common.exception.errors import ServerError
1113
from backend.core.conf import settings
1214
from backend.utils.import_parse import dynamic_import_data_model
1315

1416
if TYPE_CHECKING:
15-
from backend.app.admin.schema.data_rule import GetDataRuleDetail
17+
from backend.app.admin.model import DataRule
18+
19+
pass
1620

1721

1822
class RequestPermission:
@@ -47,33 +51,38 @@ async def __call__(self, request: Request) -> None:
4751
request.state.permission = self.value
4852

4953

50-
def filter_data_permission(request: Request) -> ColumnElement[bool]:
54+
async def filter_data_permission(db: AsyncSession, request: Request) -> ColumnElement[bool]:
5155
"""
5256
过滤数据权限,控制用户可见数据范围
5357
5458
使用场景:
55-
- 用户登录前台后,控制其能看到哪些数据
56-
- 根据用户角色和规则过滤数据访问权限
59+
- 控制用户能看到哪些数据
5760
61+
:param db: 数据库会话
5862
:param request: FastAPI 请求对象
5963
:return:
6064
"""
61-
# 获取用户角色和规则
62-
data_rules = []
65+
# 获取用户角色和数据范围
66+
data_scopes = []
6367
for role in request.user.roles:
64-
data_rules.extend(role.rules)
65-
user_data_rules: list[GetDataRuleDetail] = list(dict.fromkeys(data_rules))
68+
data_scopes.extend(role.scopes)
6669

6770
# 超级管理员和无规则用户不做过滤
68-
if request.user.is_superuser or not user_data_rules:
71+
if request.user.is_superuser or not data_scopes:
6972
return or_(1 == 1)
7073

74+
# 获取数据范围规则
75+
data_rule_list: list[DataRule] = []
76+
for data_scope in data_scopes:
77+
data_scope_with_relation = await data_scope_dao.get_with_relation(db, data_scope.id)
78+
data_rule_list.extend(data_scope_with_relation.rules)
79+
7180
where_and_list = []
7281
where_or_list = []
7382

74-
for rule in user_data_rules:
83+
for data_rule in list(dict.fromkeys(data_rule_list)):
7584
# 验证规则模型
76-
rule_model = rule.model
85+
rule_model = data_rule.model
7786
if rule_model not in settings.DATA_PERMISSION_MODELS:
7887
raise errors.NotFoundError(msg='数据规则模型不存在')
7988
model_ins = dynamic_import_data_model(settings.DATA_PERMISSION_MODELS[rule_model])
@@ -82,38 +91,38 @@ def filter_data_permission(request: Request) -> ColumnElement[bool]:
8291
model_columns = [
8392
key for key in model_ins.__table__.columns.keys() if key not in settings.DATA_PERMISSION_COLUMN_EXCLUDE
8493
]
85-
column = rule.column
94+
column = data_rule.column
8695
if column not in model_columns:
8796
raise errors.NotFoundError(msg='数据规则模型列不存在')
8897

8998
# 构建过滤条件
9099
column_obj = getattr(model_ins, column)
91-
rule_expression = rule.expression
100+
rule_expression = data_rule.expression
92101
condition = None
93102
if rule_expression == RoleDataRuleExpressionType.eq:
94-
condition = column_obj == rule.value
103+
condition = column_obj == data_rule.value
95104
elif rule_expression == RoleDataRuleExpressionType.ne:
96-
condition = column_obj != rule.value
105+
condition = column_obj != data_rule.value
97106
elif rule_expression == RoleDataRuleExpressionType.gt:
98-
condition = column_obj > rule.value
107+
condition = column_obj > data_rule.value
99108
elif rule_expression == RoleDataRuleExpressionType.ge:
100-
condition = column_obj >= rule.value
109+
condition = column_obj >= data_rule.value
101110
elif rule_expression == RoleDataRuleExpressionType.lt:
102-
condition = column_obj < rule.value
111+
condition = column_obj < data_rule.value
103112
elif rule_expression == RoleDataRuleExpressionType.le:
104-
condition = column_obj <= rule.value
113+
condition = column_obj <= data_rule.value
105114
elif rule_expression == RoleDataRuleExpressionType.in_:
106-
values = rule.value.split(',') if isinstance(rule.value, str) else rule.value
115+
values = data_rule.value.split(',') if isinstance(data_rule.value, str) else data_rule.value
107116
condition = column_obj.in_(values)
108-
elif rule.expression == RoleDataRuleExpressionType.not_in:
109-
values = rule.value.split(',') if isinstance(rule.value, str) else rule.value
117+
elif data_rule.expression == RoleDataRuleExpressionType.not_in:
118+
values = data_rule.value.split(',') if isinstance(data_rule.value, str) else data_rule.value
110119
condition = ~column_obj.in_(values)
111120

112121
# 根据运算符添加到对应列表
113122
if condition is not None:
114-
if rule.operator == RoleDataRuleOperatorType.AND:
123+
if data_rule.operator == RoleDataRuleOperatorType.AND:
115124
where_and_list.append(condition)
116-
elif rule.operator == RoleDataRuleOperatorType.OR:
125+
elif data_rule.operator == RoleDataRuleOperatorType.OR:
117126
where_or_list.append(condition)
118127

119128
# 组合所有条件

backend/plugin/casbin/crud/crud_api.py

Lines changed: 1 addition & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -7,7 +7,6 @@
77
from sqlalchemy.ext.asyncio import AsyncSession
88
from sqlalchemy_crud_plus import CRUDPlus
99

10-
from backend.common.security.permission import filter_data_permission
1110
from backend.plugin.casbin.model import Api
1211
from backend.plugin.casbin.schema.api import CreateApiParam, UpdateApiParam
1312

@@ -43,7 +42,7 @@ async def get_list(self, request: Request, name: str = None, method: str = None,
4342
if path is not None:
4443
filters.update(path__like=f'%{path}%')
4544
stmt = await self.select_order('created_time', 'desc', **filters)
46-
return stmt.where(filter_data_permission(request))
45+
return stmt
4746

4847
async def get_all(self, db: AsyncSession) -> Sequence[Api]:
4948
"""

0 commit comments

Comments
 (0)