Skip to content

Commit 5d680ff

Browse files
authored
Optimize data permission logic and usage (#947)
* Optimize data permission rules and usage * Update get data permission models * Update date permission filter * Optimize the target model logic * Upgrade dependencies to use latest features * Remove model warnings * Fix the latest feature issues * Fix the sqlalchemy Table class import * Fix the sqlalchemy Table class compatibility
1 parent 866b0e6 commit 5d680ff

File tree

15 files changed

+243
-182
lines changed

15 files changed

+243
-182
lines changed

backend/__init__.py

Lines changed: 16 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1 +1,17 @@
1+
import sqlalchemy as sa
2+
3+
from backend.utils.import_parse import get_all_models
4+
5+
# import all models for auto create db tables
6+
for cls in get_all_models():
7+
if isinstance(cls, sa.Table):
8+
table_name = cls.name
9+
if table_name not in globals():
10+
globals()[table_name] = cls
11+
else:
12+
class_name = cls.__name__
13+
if class_name not in globals():
14+
globals()[class_name] = cls
15+
16+
117
__version__ = '1.11.2'

backend/alembic/env.py

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -8,17 +8,9 @@
88
from sqlalchemy.engine import Connection
99
from sqlalchemy.ext.asyncio import async_engine_from_config
1010

11-
from backend.app import get_app_models
1211
from backend.common.model import MappedBase
1312
from backend.core import path_conf
1413
from backend.database.db import SQLALCHEMY_DATABASE_URL
15-
from backend.plugin.tools import get_plugin_models
16-
17-
# import models
18-
for cls in get_app_models() + get_plugin_models():
19-
class_name = cls.__name__
20-
if class_name not in globals():
21-
globals()[class_name] = cls
2214

2315
if not os.path.exists(path_conf.ALEMBIC_VERSION_DIR):
2416
os.makedirs(path_conf.ALEMBIC_VERSION_DIR)

backend/app/__init__.py

Lines changed: 0 additions & 28 deletions
Original file line numberDiff line numberDiff line change
@@ -1,28 +0,0 @@
1-
import os.path
2-
3-
from backend.core.path_conf import BASE_PATH
4-
from backend.utils.import_parse import get_model_objects
5-
6-
7-
def get_app_models() -> list[type]:
8-
"""获取 app 所有模型类"""
9-
app_path = BASE_PATH / 'app'
10-
list_dirs = os.listdir(app_path)
11-
12-
apps = [d for d in list_dirs if os.path.isdir(os.path.join(app_path, d)) and d != '__pycache__']
13-
14-
objs = []
15-
for app in apps:
16-
module_path = f'backend.app.{app}.model'
17-
obj = get_model_objects(module_path)
18-
if obj:
19-
objs.extend(obj)
20-
21-
return objs
22-
23-
24-
# import all app models for auto create db tables
25-
for cls in get_app_models():
26-
class_name = cls.__name__
27-
if class_name not in globals():
28-
globals()[class_name] = cls

backend/app/admin/api/v1/sys/dept.py

Lines changed: 6 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -1,12 +1,14 @@
11
from typing import Annotated
22

3-
from fastapi import APIRouter, Depends, Path, Query, Request
3+
from fastapi import APIRouter, Depends, Path, Query
4+
from sqlalchemy import ColumnElement
45

6+
from backend.app.admin.model import Dept
57
from backend.app.admin.schema.dept import CreateDeptParam, GetDeptDetail, GetDeptTree, UpdateDeptParam
68
from backend.app.admin.service.dept_service import dept_service
79
from backend.common.response.response_schema import ResponseModel, ResponseSchemaModel, response_base
810
from backend.common.security.jwt import DependsJwtAuth
9-
from backend.common.security.permission import RequestPermission
11+
from backend.common.security.permission import DataPermissionFilter, RequestPermission
1012
from backend.common.security.rbac import DependsRBAC
1113
from backend.database.db import CurrentSession, CurrentSessionTransaction
1214

@@ -24,14 +26,14 @@ async def get_dept(
2426
@router.get('', summary='获取部门树', dependencies=[DependsJwtAuth])
2527
async def get_dept_tree(
2628
db: CurrentSession,
27-
request: Request,
29+
data_filter: Annotated[ColumnElement[bool], Depends(DataPermissionFilter(Dept))],
2830
name: Annotated[str | None, Query(description='部门名称')] = None,
2931
leader: Annotated[str | None, Query(description='部门负责人')] = None,
3032
phone: Annotated[str | None, Query(description='联系电话')] = None,
3133
status: Annotated[int | None, Query(description='状态')] = None,
3234
) -> ResponseSchemaModel[list[GetDeptTree]]:
3335
dept = await dept_service.get_tree(
34-
db=db, request_user=request.user, name=name, leader=leader, phone=phone, status=status
36+
db=db, data_filter=data_filter, name=name, leader=leader, phone=phone, status=status
3537
)
3638
return response_base.success(data=dept)
3739

backend/app/admin/crud/crud_dept.py

Lines changed: 3 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,13 +1,12 @@
11
from collections.abc import Sequence
22
from typing import Any
33

4+
from sqlalchemy import ColumnElement
45
from sqlalchemy.ext.asyncio import AsyncSession
56
from sqlalchemy_crud_plus import CRUDPlus, JoinConfig
67

78
from backend.app.admin.model import Dept, User
89
from backend.app.admin.schema.dept import CreateDeptParam, UpdateDeptParam
9-
from backend.app.admin.schema.user import GetUserInfoWithRelationDetail
10-
from backend.common.security.permission import filter_data_permission
1110
from backend.utils.serializers import select_join_serialize
1211

1312

@@ -37,7 +36,7 @@ async def get_by_name(self, db: AsyncSession, name: str) -> Dept | None:
3736
async def get_all(
3837
self,
3938
db: AsyncSession,
40-
request_user: GetUserInfoWithRelationDetail,
39+
data_filter: ColumnElement[bool],
4140
name: str | None,
4241
leader: str | None,
4342
phone: str | None,
@@ -47,7 +46,7 @@ async def get_all(
4746
获取所有部门
4847
4948
:param db: 数据库会话
50-
:param request_user: 请求用户
49+
:param data_filter: 请求用户
5150
:param name: 部门名称
5251
:param leader: 负责人
5352
:param phone: 联系电话
@@ -65,7 +64,6 @@ async def get_all(
6564
if status is not None:
6665
filters['status'] = status
6766

68-
data_filter = filter_data_permission(request_user)
6967
return await self.select_models_order(db, 'sort', 'desc', data_filter, **filters)
7068

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

backend/app/admin/schema/data_rule.py

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -45,4 +45,4 @@ class GetDataRuleColumnDetail(SchemaBase):
4545
"""数据规则可用模型字段详情"""
4646

4747
key: str = Field(description='字段名')
48-
comment: str = Field(description='字段评论')
48+
comment: str | None = Field(description='字段评论')

backend/app/admin/service/data_rule_service.py

Lines changed: 9 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,7 @@
11
from collections.abc import Sequence
22
from typing import Any
33

4+
from sqlalchemy import Table
45
from sqlalchemy.ext.asyncio import AsyncSession
56

67
from backend.app.admin.crud.crud_data_rule import data_rule_dao
@@ -14,8 +15,8 @@
1415
from backend.app.admin.utils.cache import user_cache_manager
1516
from backend.common.exception import errors
1617
from backend.common.pagination import paging_data
18+
from backend.common.security.permission import get_data_permission_models
1719
from backend.core.conf import settings
18-
from backend.utils.import_parse import dynamic_import_data_model
1920

2021

2122
class DataRuleService:
@@ -39,7 +40,8 @@ async def get(*, db: AsyncSession, pk: int) -> DataRule:
3940
@staticmethod
4041
async def get_models() -> list[str]:
4142
"""获取所有数据规则可用模型"""
42-
return list(settings.DATA_PERMISSION_MODELS.keys())
43+
model_exclude = ['DataScope', 'DataRule', 'sys_role_data_scope', 'sys_data_scope_rule']
44+
return [m for m in list(get_data_permission_models().keys()) if m not in model_exclude]
4345

4446
@staticmethod
4547
async def get_columns(model: str) -> list[GetDataRuleColumnDetail]:
@@ -49,13 +51,15 @@ async def get_columns(model: str) -> list[GetDataRuleColumnDetail]:
4951
:param model: 模型名称
5052
:return:
5153
"""
52-
if model not in settings.DATA_PERMISSION_MODELS:
54+
available_models = get_data_permission_models()
55+
if model not in available_models:
5356
raise errors.NotFoundError(msg='数据规则可用模型不存在')
54-
model_ins = dynamic_import_data_model(settings.DATA_PERMISSION_MODELS[model])
57+
model_ins = available_models[model]
5558

59+
table = model_ins if isinstance(model_ins, Table) else model_ins.__table__
5660
model_columns = [
5761
GetDataRuleColumnDetail(key=column.key, comment=column.comment)
58-
for column in model_ins.__table__.columns
62+
for column in table.columns
5963
if column.key not in settings.DATA_PERMISSION_COLUMN_EXCLUDE
6064
]
6165
return model_columns

backend/app/admin/service/dept_service.py

Lines changed: 4 additions & 5 deletions
Original file line numberDiff line numberDiff line change
@@ -1,11 +1,11 @@
11
from typing import Any
22

3+
from sqlalchemy import ColumnElement
34
from sqlalchemy.ext.asyncio import AsyncSession
45

56
from backend.app.admin.crud.crud_dept import dept_dao
67
from backend.app.admin.model import Dept
78
from backend.app.admin.schema.dept import CreateDeptParam, UpdateDeptParam
8-
from backend.app.admin.schema.user import GetUserInfoWithRelationDetail
99
from backend.common.exception import errors
1010
from backend.core.conf import settings
1111
from backend.database.redis import redis_client
@@ -34,7 +34,7 @@ async def get(*, db: AsyncSession, pk: int) -> Dept:
3434
async def get_tree(
3535
*,
3636
db: AsyncSession,
37-
request_user: GetUserInfoWithRelationDetail,
37+
data_filter: ColumnElement[bool],
3838
name: str | None,
3939
leader: str | None,
4040
phone: str | None,
@@ -44,15 +44,14 @@ async def get_tree(
4444
获取部门树形结构
4545
4646
:param db: 数据库会话
47-
:param request_user: 请求用户
47+
:param data_filter: 请求用户
4848
:param name: 部门名称
4949
:param leader: 部门负责人
5050
:param phone: 联系电话
5151
:param status: 状态
5252
:return:
5353
"""
54-
55-
dept_select = await dept_dao.get_all(db, request_user, name, leader, phone, status)
54+
dept_select = await dept_dao.get_all(db, data_filter, name, leader, phone, status)
5655
tree_data = get_tree_data(dept_select)
5756
return tree_data
5857

0 commit comments

Comments
 (0)