Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
2 changes: 1 addition & 1 deletion backend/app/admin/crud/crud_dept.py
Original file line number Diff line number Diff line change
Expand Up @@ -63,7 +63,7 @@ async def get_all(
if status is not None:
filters['status'] = status

data_filtered = await filter_data_permission(db, request_user)
data_filtered = filter_data_permission(request_user)
return await self.select_models_order(db, 'sort', 'desc', data_filtered, **filters)

async def create(self, db: AsyncSession, obj: CreateDeptParam) -> None:
Expand Down
9 changes: 7 additions & 2 deletions backend/app/admin/crud/crud_user.py
Original file line number Diff line number Diff line change
Expand Up @@ -6,7 +6,7 @@
from sqlalchemy.sql import Select
from sqlalchemy_crud_plus import CRUDPlus

from backend.app.admin.model import Dept, Role, User
from backend.app.admin.model import DataScope, Dept, Role, User
from backend.app.admin.schema.user import (
AddOAuth2UserParam,
AddUserParam,
Expand Down Expand Up @@ -281,7 +281,12 @@ async def get_with_relation(

return await self.select_model_by_column(
db,
load_options=[selectinload(self.model.roles).options(selectinload(Role.menus), selectinload(Role.scopes))],
load_options=[
selectinload(self.model.roles).options(
selectinload(Role.menus),
selectinload(Role.scopes).options(selectinload(DataScope.rules)),
)
],
load_strategies=['dept'],
**filters,
)
Expand Down
2 changes: 1 addition & 1 deletion backend/app/admin/schema/data_rule.py
Original file line number Diff line number Diff line change
Expand Up @@ -34,7 +34,7 @@ class DeleteDataRuleParam(SchemaBase):
class GetDataRuleDetail(DataRuleSchemaBase):
"""数据规则详情"""

model_config = ConfigDict(from_attributes=True)
model_config = ConfigDict(from_attributes=True, frozen=True)

id: int = Field(description='规则 ID')
created_time: datetime = Field(description='创建时间')
Expand Down
2 changes: 1 addition & 1 deletion backend/app/admin/schema/data_scope.py
Original file line number Diff line number Diff line change
Expand Up @@ -47,4 +47,4 @@ class GetDataScopeDetail(DataScopeBase):
class GetDataScopeWithRelationDetail(GetDataScopeDetail):
"""数据范围关联详情"""

rules: list[GetDataRuleDetail] = Field([], description='数据规则列表')
rules: list[GetDataRuleDetail | None] = Field([], description='数据规则列表')
4 changes: 2 additions & 2 deletions backend/app/admin/schema/role.py
Original file line number Diff line number Diff line change
Expand Up @@ -2,7 +2,7 @@

from pydantic import ConfigDict, Field

from backend.app.admin.schema.data_scope import GetDataScopeDetail
from backend.app.admin.schema.data_scope import GetDataScopeWithRelationDetail
from backend.app.admin.schema.menu import GetMenuDetail
from backend.common.enums import StatusType
from backend.common.schema import SchemaBase
Expand Down Expand Up @@ -57,4 +57,4 @@ class GetRoleWithRelationDetail(GetRoleDetail):
"""角色关联详情"""

menus: list[GetMenuDetail | None] = Field([], description='菜单详情列表')
scopes: list[GetDataScopeDetail | None] = Field([], description='数据范围列表')
scopes: list[GetDataScopeWithRelationDetail | None] = Field([], description='数据范围列表')
25 changes: 6 additions & 19 deletions backend/common/security/permission.py
Original file line number Diff line number Diff line change
@@ -1,8 +1,6 @@
from fastapi import Request
from sqlalchemy import ColumnElement, and_, or_
from sqlalchemy.ext.asyncio import AsyncSession

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


async def filter_data_permission(db: AsyncSession, request_user: GetUserInfoWithRelationDetail) -> ColumnElement[bool]: # noqa: C901
def filter_data_permission(request_user: GetUserInfoWithRelationDetail) -> ColumnElement[bool]: # noqa: C901
"""
过滤数据权限,控制用户可见数据范围

使用场景:
- 控制用户能看到哪些数据

:param db: 数据库会话
:param request_user: 请求用户
:return:
"""
Expand All @@ -62,31 +59,21 @@ async def filter_data_permission(db: AsyncSession, request_user: GetUserInfoWith
if not role.is_filter_scopes:
return or_(1 == 1)

# 获取数据范围
data_scope_ids = set()
# 获取数据规则
data_rules = set()
for role in request_user.roles:
for scope in role.scopes:
if scope.status:
data_scope_ids.add(scope.id)
data_rules.update(scope.rules)

# 无规则用户不做过滤
if not list(data_scope_ids):
if not list(data_rules):
return or_(1 == 1)

# 获取数据范围规则
unique_data_rules = {}
for data_scope_id in list(data_scope_ids):
data_scope_with_relation = await data_scope_dao.get_with_relation(db, data_scope_id)
for rule in data_scope_with_relation.rules:
unique_data_rules[rule.id] = rule

# 转换为列表
data_rule_list = list(unique_data_rules.values())

where_and_list = []
where_or_list = []

for data_rule in data_rule_list:
for data_rule in list(data_rules):
# 验证规则模型
rule_model = data_rule.model
if rule_model not in settings.DATA_PERMISSION_MODELS:
Expand Down
5 changes: 5 additions & 0 deletions backend/sql/mysql/init_test_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ values
(1, '部门名称等于测试', '部门', 'name', 1, 0, '测试', now(), null),
(2, '父部门 ID 等于 1', '部门', 'parent_id', 0, 0, '1', now(), null);

insert into sys_role_data_scope (id, role_id, data_scope_id)
values
(1, 1, 1),
(2, 1, 2);

insert into sys_data_scope_rule (id, data_scope_id, data_rule_id)
values
(1, 1, 1),
Expand Down
6 changes: 6 additions & 0 deletions backend/sql/postgresql/init_test_data.sql
Original file line number Diff line number Diff line change
Expand Up @@ -111,6 +111,11 @@ values
(1, '部门名称等于测试', '部门', 'name', 1, 0, '测试', now(), null),
(2, '父部门 ID 等于 1', '部门', 'parent_id', 0, 0, '1', now(), null);

insert into sys_role_data_scope (id, role_id, data_scope_id)
values
(1, 1, 1),
(2, 1, 2);

insert into sys_data_scope_rule (id, data_scope_id, data_rule_id)
values
(1, 1, 1),
Expand All @@ -125,4 +130,5 @@ select setval(pg_get_serial_sequence('sys_user', 'id'),coalesce(max(id), 0) + 1,
select setval(pg_get_serial_sequence('sys_user_role', 'id'),coalesce(max(id), 0) + 1, true) from sys_user_role;
select setval(pg_get_serial_sequence('sys_data_scope', 'id'),coalesce(max(id), 0) + 1, true) from sys_data_scope;
select setval(pg_get_serial_sequence('sys_data_rule', 'id'),coalesce(max(id), 0) + 1, true) from sys_data_rule;
select setval(pg_get_serial_sequence('sys_role_data_scope', 'id'),coalesce(max(id), 0) + 1, true) from sys_role_data_scope;
select setval(pg_get_serial_sequence('sys_data_scope_rule', 'id'),coalesce(max(id), 0) + 1, true) from sys_data_scope_rule;