Skip to content

Commit 0ea213e

Browse files
authored
Optimize the data permission condition build (#904)
1 parent 292f5d7 commit 0ea213e

File tree

8 files changed

+29
-26
lines changed

8 files changed

+29
-26
lines changed

backend/app/admin/crud/crud_dept.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -63,7 +63,7 @@ async def get_all(
6363
if status is not None:
6464
filters['status'] = status
6565

66-
data_filtered = await filter_data_permission(db, request_user)
66+
data_filtered = filter_data_permission(request_user)
6767
return await self.select_models_order(db, 'sort', 'desc', data_filtered, **filters)
6868

6969
async def create(self, db: AsyncSession, obj: CreateDeptParam) -> None:

backend/app/admin/crud/crud_user.py

Lines changed: 7 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -6,7 +6,7 @@
66
from sqlalchemy.sql import Select
77
from sqlalchemy_crud_plus import CRUDPlus
88

9-
from backend.app.admin.model import Dept, Role, User
9+
from backend.app.admin.model import DataScope, Dept, Role, User
1010
from backend.app.admin.schema.user import (
1111
AddOAuth2UserParam,
1212
AddUserParam,
@@ -281,7 +281,12 @@ async def get_with_relation(
281281

282282
return await self.select_model_by_column(
283283
db,
284-
load_options=[selectinload(self.model.roles).options(selectinload(Role.menus), selectinload(Role.scopes))],
284+
load_options=[
285+
selectinload(self.model.roles).options(
286+
selectinload(Role.menus),
287+
selectinload(Role.scopes).options(selectinload(DataScope.rules)),
288+
)
289+
],
285290
load_strategies=['dept'],
286291
**filters,
287292
)

backend/app/admin/schema/data_rule.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -34,7 +34,7 @@ class DeleteDataRuleParam(SchemaBase):
3434
class GetDataRuleDetail(DataRuleSchemaBase):
3535
"""数据规则详情"""
3636

37-
model_config = ConfigDict(from_attributes=True)
37+
model_config = ConfigDict(from_attributes=True, frozen=True)
3838

3939
id: int = Field(description='规则 ID')
4040
created_time: datetime = Field(description='创建时间')

backend/app/admin/schema/data_scope.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,4 +47,4 @@ class GetDataScopeDetail(DataScopeBase):
4747
class GetDataScopeWithRelationDetail(GetDataScopeDetail):
4848
"""数据范围关联详情"""
4949

50-
rules: list[GetDataRuleDetail] = Field([], description='数据规则列表')
50+
rules: list[GetDataRuleDetail | None] = Field([], description='数据规则列表')

backend/app/admin/schema/role.py

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -2,7 +2,7 @@
22

33
from pydantic import ConfigDict, Field
44

5-
from backend.app.admin.schema.data_scope import GetDataScopeDetail
5+
from backend.app.admin.schema.data_scope import GetDataScopeWithRelationDetail
66
from backend.app.admin.schema.menu import GetMenuDetail
77
from backend.common.enums import StatusType
88
from backend.common.schema import SchemaBase
@@ -57,4 +57,4 @@ class GetRoleWithRelationDetail(GetRoleDetail):
5757
"""角色关联详情"""
5858

5959
menus: list[GetMenuDetail | None] = Field([], description='菜单详情列表')
60-
scopes: list[GetDataScopeDetail | None] = Field([], description='数据范围列表')
60+
scopes: list[GetDataScopeWithRelationDetail | None] = Field([], description='数据范围列表')

backend/common/security/permission.py

Lines changed: 6 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -1,8 +1,6 @@
11
from fastapi import Request
22
from sqlalchemy import ColumnElement, and_, or_
3-
from sqlalchemy.ext.asyncio import AsyncSession
43

5-
from backend.app.admin.crud.crud_data_scope import data_scope_dao
64
from backend.app.admin.schema.user import GetUserInfoWithRelationDetail
75
from backend.common.context import ctx
86
from backend.common.enums import RoleDataRuleExpressionType, RoleDataRuleOperatorType
@@ -43,14 +41,13 @@ async def __call__(self, request: Request) -> None:
4341
ctx.permission = self.value
4442

4543

46-
async def filter_data_permission(db: AsyncSession, request_user: GetUserInfoWithRelationDetail) -> ColumnElement[bool]: # noqa: C901
44+
def filter_data_permission(request_user: GetUserInfoWithRelationDetail) -> ColumnElement[bool]: # noqa: C901
4745
"""
4846
过滤数据权限,控制用户可见数据范围
4947
5048
使用场景:
5149
- 控制用户能看到哪些数据
5250
53-
:param db: 数据库会话
5451
:param request_user: 请求用户
5552
:return:
5653
"""
@@ -62,31 +59,21 @@ async def filter_data_permission(db: AsyncSession, request_user: GetUserInfoWith
6259
if not role.is_filter_scopes:
6360
return or_(1 == 1)
6461

65-
# 获取数据范围
66-
data_scope_ids = set()
62+
# 获取数据规则
63+
data_rules = set()
6764
for role in request_user.roles:
6865
for scope in role.scopes:
6966
if scope.status:
70-
data_scope_ids.add(scope.id)
67+
data_rules.update(scope.rules)
7168

7269
# 无规则用户不做过滤
73-
if not list(data_scope_ids):
70+
if not list(data_rules):
7471
return or_(1 == 1)
7572

76-
# 获取数据范围规则
77-
unique_data_rules = {}
78-
for data_scope_id in list(data_scope_ids):
79-
data_scope_with_relation = await data_scope_dao.get_with_relation(db, data_scope_id)
80-
for rule in data_scope_with_relation.rules:
81-
unique_data_rules[rule.id] = rule
82-
83-
# 转换为列表
84-
data_rule_list = list(unique_data_rules.values())
85-
8673
where_and_list = []
8774
where_or_list = []
8875

89-
for data_rule in data_rule_list:
76+
for data_rule in list(data_rules):
9077
# 验证规则模型
9178
rule_model = data_rule.model
9279
if rule_model not in settings.DATA_PERMISSION_MODELS:

backend/sql/mysql/init_test_data.sql

Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ values
111111
(1, '部门名称等于测试', '部门', 'name', 1, 0, '测试', now(), null),
112112
(2, '父部门 ID 等于 1', '部门', 'parent_id', 0, 0, '1', now(), null);
113113

114+
insert into sys_role_data_scope (id, role_id, data_scope_id)
115+
values
116+
(1, 1, 1),
117+
(2, 1, 2);
118+
114119
insert into sys_data_scope_rule (id, data_scope_id, data_rule_id)
115120
values
116121
(1, 1, 1),

backend/sql/postgresql/init_test_data.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -111,6 +111,11 @@ values
111111
(1, '部门名称等于测试', '部门', 'name', 1, 0, '测试', now(), null),
112112
(2, '父部门 ID 等于 1', '部门', 'parent_id', 0, 0, '1', now(), null);
113113

114+
insert into sys_role_data_scope (id, role_id, data_scope_id)
115+
values
116+
(1, 1, 1),
117+
(2, 1, 2);
118+
114119
insert into sys_data_scope_rule (id, data_scope_id, data_rule_id)
115120
values
116121
(1, 1, 1),
@@ -125,4 +130,5 @@ select setval(pg_get_serial_sequence('sys_user', 'id'),coalesce(max(id), 0) + 1,
125130
select setval(pg_get_serial_sequence('sys_user_role', 'id'),coalesce(max(id), 0) + 1, true) from sys_user_role;
126131
select setval(pg_get_serial_sequence('sys_data_scope', 'id'),coalesce(max(id), 0) + 1, true) from sys_data_scope;
127132
select setval(pg_get_serial_sequence('sys_data_rule', 'id'),coalesce(max(id), 0) + 1, true) from sys_data_rule;
133+
select setval(pg_get_serial_sequence('sys_role_data_scope', 'id'),coalesce(max(id), 0) + 1, true) from sys_role_data_scope;
128134
select setval(pg_get_serial_sequence('sys_data_scope_rule', 'id'),coalesce(max(id), 0) + 1, true) from sys_data_scope_rule;

0 commit comments

Comments
 (0)