refactor: 完成项目大规模重构与功能优化

这是一次综合性的项目迭代,包含以下核心变更:
1.  **目录与模块重构**
    - 调整工作流节点类型模块目录结构,迁移节点类型相关代码
    - 重命名platform模块为system模块,更新插件配置信息
    - 重构代码生成模块导入路径
2.  **数据库与CRUD优化**
    - 统一所有CRUD类构造函数,新增数据库会话参数
    - 修复权限过滤器数据库会话使用问题
    - 更新模板生成器的CRUD代码模板
3.  **认证与安全改进**
    - 重构JWT密钥配置,移除默认密钥强制要求环境变量
    - 重命名密码工具类,统一密码加密校验逻辑
    - 优化OAuth认证流程,修复匿名认证使用问题
4.  **前端与静态资源**
    - 重构前端挂载逻辑,增加目录存在性校验
    - 使用标准StaticFiles替换自定义前端挂载实现
5.  **工具类与依赖更新**
    - 修复导入工具的表名重复检测逻辑
    - 优化限流回调代码,移除冗余依赖
    - 更新用户、租户等模块的响应模型字段
6.  **数据与配置修正**
    - 修复系统版本数据字段命名不统一问题
    - 简化枚举类校验逻辑,移除冗余注释
    - 修复测试用例中的密码工具类导入错误
This commit is contained in:
zhangtao
2026-07-11 13:03:28 +08:00
parent 5ff72b086f
commit 6a5f8cf0dd
95 changed files with 1531 additions and 1118 deletions
@@ -11,10 +11,7 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.common.response import ErrorResponse, RedirectContentResponse, ResponseSchema, SuccessResponse
from app.config.setting import settings
from app.core.base_schema import (
AuthSchema,
JWTOutSchema,
)
from app.core.base_schema import AuthSchema, JWTOutSchema
from app.core.dependencies import db_getter, get_current_user, redis_getter
from app.core.exceptions import CustomException
from app.core.logger import logger
@@ -128,9 +125,10 @@ async def select_tenant_controller(
request: Request,
auth: Annotated[AuthSchema, Depends(get_current_user)],
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
data: Annotated[SelectTenantSchema, Body(description="租户选择参数")],
) -> JSONResponse:
result = await LoginService(auth).select_tenant(request=request, redis=redis, tenant_id=data.tenant_id)
result = await LoginService(auth, db).select_tenant(request=request, redis=redis, tenant_id=data.tenant_id)
await FastAPICache.clear(namespace=_AUTH_TENANTS_NS)
return SuccessResponse(data=result, msg="租户切换成功")
@@ -140,8 +138,9 @@ async def enter_platform_controller(
request: Request,
auth: Annotated[AuthSchema, Depends(get_current_user)],
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
) -> JSONResponse:
result = await LoginService(auth).enter_platform(request=request, redis=redis)
result = await LoginService(auth, db).enter_platform(request=request, redis=redis)
await FastAPICache.clear(namespace=_AUTH_TENANTS_NS)
return SuccessResponse(data=result, msg="已返回平台管理模式")
@@ -150,8 +149,9 @@ async def enter_platform_controller(
@cache(expire=120, namespace=_AUTH_TENANTS_NS)
async def get_user_tenants_controller(
auth: Annotated[AuthSchema, Depends(get_current_user)],
db: Annotated[AsyncSession, Depends(db_getter)],
) -> JSONResponse:
service = LoginService(auth)
service = LoginService(auth, db)
tenants = await service.get_user_tenants()
return SuccessResponse(data=tenants, msg="获取租户列表成功")
@@ -161,9 +161,10 @@ async def impersonate_controller(
request: Request,
auth: Annotated[AuthSchema, Depends(get_current_user)],
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
data: Annotated[ImpersonateSchema, Body(description="代签入参数")],
) -> JSONResponse:
result = await LoginService(auth).impersonate(request=request, redis=redis, tenant_id=data.tenant_id)
result = await LoginService(auth, db).impersonate(request=request, redis=redis, tenant_id=data.tenant_id)
await FastAPICache.clear(namespace=_AUTH_TENANTS_NS)
return SuccessResponse(data=result, msg="代签入成功")
@@ -306,9 +306,9 @@ async def ensure_oauth_user(
unique_id: str,
display_name: str,
) -> UserModel:
auth = AuthSchema.anonymous(db=db)
auth = AuthSchema(check_data_scope=False)
username = _username_for_oauth(provider, unique_id)
existing = await UserCRUD(auth).get(username=username)
existing = await UserCRUD(auth, db).get(username=username)
if existing:
return existing
@@ -319,14 +319,14 @@ async def ensure_oauth_user(
role_ids=list(settings.OAUTH_DEFAULT_ROLE_IDS),
)
try:
await UserService(auth).create(data=reg)
await UserService(auth, db).create(data=reg)
except Exception:
# 并发创建可能触发唯一约束冲突,回退到再次查询
existing = await UserCRUD(auth).get(username=username)
existing = await UserCRUD(auth, db).get(username=username)
if existing:
return existing
raise CustomException(msg="OAuth 注册失败")
user = await UserCRUD(auth).get(username=username)
user = await UserCRUD(auth, db).get(username=username)
if not user:
raise CustomException(msg="OAuth 注册失败")
logger.info(f"OAuth 自动注册用户: {username} ({provider})")
@@ -381,7 +381,7 @@ async def complete_oauth_login(
if user.status == 1:
raise CustomException(msg="用户已被停用")
user = await UserCRUD(AuthSchema.anonymous(db=db)).update_last_login(id=user.id)
user = await UserCRUD(AuthSchema(check_data_scope=False), db).update_last_login(id=user.id)
if not user:
raise CustomException(msg="用户不存在")
@@ -2,8 +2,23 @@ from typing import Any
from pydantic import BaseModel, ConfigDict, EmailStr, Field
from app.core.base_schema import JWTOutSchema
from app.core.base_schema import AuthSchema, CoreUserSchema, JWTOutSchema
__all__ = [
"AuthSchema",
"CoreUserSchema",
"CaptchaOutSchema",
"TenantOptionSchema",
"SelectTenantSchema",
"SelectTenantOutSchema",
"LoginWithTenantsSchema",
"TenantRegisterSchema",
"TenantRegisterOutSchema",
"EnterPlatformOutSchema",
"TenantLookupOutSchema",
"ImpersonateSchema",
"ImpersonateOutSchema",
]
class CaptchaOutSchema(BaseModel):
"""验证码响应模型"""
@@ -10,13 +10,10 @@ from sqlalchemy.ext.asyncio import AsyncSession
from app.api.v1.module_system.user.crud import UserCRUD
from app.api.v1.module_system.user.model import UserModel
from app.api.v1.module_system.user.schema import UserOutSchema
from app.common.enums import RedisInitKeyConfig
from app.config.setting import settings
from app.core.base_schema import (
AuthSchema,
JWTOutSchema,
JWTPayloadSchema,
)
from app.core.base_schema import AuthSchema, JWTOutSchema, JWTPayloadSchema
from app.core.exceptions import CustomException
from app.core.logger import logger
from app.core.redis_crud import RedisCURD
@@ -27,7 +24,7 @@ from app.core.security import (
)
from app.utils.captcha_util import CaptchaUtil
from app.utils.common_util import get_random_character
from app.utils.hash_bcrpy_util import PwdUtil
from app.utils.password_util import PwdUtil
from app.utils.ip_local_util import IpLocalUtil, get_client_ip
from .schema import (
@@ -60,8 +57,8 @@ async def _write_login_log(
try:
async with async_db_session() as session, session.begin():
_auth = AuthSchema.anonymous(db=session)
obj = await LoginLogCRUD(_auth).create(
_auth = AuthSchema(check_data_scope=False)
obj = await LoginLogCRUD(_auth, session).create(
data=LoginLogCreateSchema(
username=username,
status=status,
@@ -101,8 +98,9 @@ async def _async_fill_login_location(redis, login_log_id: int, ip: str | None) -
class LoginService:
"""登录认证服务"""
def __init__(self, auth: AuthSchema) -> None:
def __init__(self, auth: AuthSchema, db: AsyncSession) -> None:
self.auth = auth
self.db = db
@classmethod
async def authenticate_user(
@@ -133,8 +131,8 @@ class LoginService:
captcha=login_form.captcha,
)
auth = AuthSchema.anonymous(db=db)
user = await UserCRUD(auth).get(username=login_form.username)
auth = AuthSchema(check_data_scope=False)
user = await UserCRUD(auth, db).get(username=login_form.username)
if not user:
await _write_login_log(
@@ -176,7 +174,7 @@ class LoginService:
from app.api.v1.module_platform.tenant.model import TenantModel
tenant_stmt = select(TenantModel).where(TenantModel.id == user.tenant_id, TenantModel.status == 0, TenantModel.is_deleted.is_(False)).limit(1)
tenant_result = await auth.db.execute(tenant_stmt)
tenant_result = await db.execute(tenant_stmt)
if not tenant_result.scalar_one_or_none():
await _write_login_log(
username=_login_username,
@@ -189,7 +187,7 @@ class LoginService:
)
raise CustomException(msg="所属租户已被禁用,请联系平台管理员")
await UserCRUD(auth).update_last_login(id=user.id)
await UserCRUD(auth, db).update_last_login(id=user.id)
if not user:
raise CustomException(msg="用户不存在")
@@ -203,8 +201,8 @@ class LoginService:
login_type=login_form.login_type,
)
tenants_auth = AuthSchema(db=db, user=user, check_data_scope=False)
tenants = await LoginService(tenants_auth).get_user_tenants(user_id=user.id)
tenants_auth = AuthSchema(user=UserOutSchema.model_validate(user), check_data_scope=False)
tenants = await LoginService(tenants_auth, db).get_user_tenants(user_id=user.id)
user_info = {
"id": user.id,
@@ -376,8 +374,8 @@ class LoginService:
if not session_id or not user_id:
raise CustomException(msg="非法凭证,无法获取会话编号或用户ID")
auth = AuthSchema.anonymous(db=db)
user = await UserCRUD(auth).get(id=user_id)
auth = AuthSchema(check_data_scope=False)
user = await UserCRUD(auth, db).get(id=user_id)
if not user:
raise CustomException(msg="刷新token失败,用户不存在")
if user.status == 1:
@@ -464,7 +462,7 @@ class LoginService:
if user.is_superuser:
stmt = select(TenantModel).where(TenantModel.status == 0, TenantModel.is_deleted.is_(False)).order_by(TenantModel.sort, TenantModel.id)
result = await self.auth.db.execute(stmt)
result = await self.db.execute(stmt)
tenant_objs = result.scalars().all()
return [TenantOptionSchema(id=t.id, name=t.name, code=t.code) for t in tenant_objs]
@@ -478,7 +476,7 @@ class LoginService:
)
.order_by(TenantUserModel.is_default.desc(), TenantModel.sort, TenantModel.id)
)
result = await self.auth.db.execute(stmt)
result = await self.db.execute(stmt)
tenant_objs = result.scalars().all()
return [TenantOptionSchema(id=t.id, name=t.name, code=t.code) for t in tenant_objs]
@@ -506,12 +504,12 @@ class LoginService:
)
.limit(1)
)
result = await self.auth.db.execute(exist_stmt)
result = await self.db.execute(exist_stmt)
if not result.scalar_one_or_none():
raise CustomException(msg="您不属于该租户,无法切换")
tenant_stmt = select(TenantModel).where(TenantModel.id == tenant_id, TenantModel.status == 0).limit(1)
result = await self.auth.db.execute(tenant_stmt)
result = await self.db.execute(tenant_stmt)
tenant = result.scalar_one_or_none()
if not tenant:
raise CustomException(msg="租户不存在或已被禁用")
@@ -661,7 +659,7 @@ class LoginService:
raise CustomException(msg="仅平台管理员可执行代签入")
tenant_stmt = select(TenantModel).where(TenantModel.id == tenant_id, TenantModel.is_deleted.is_(False)).limit(1)
result = await self.auth.db.execute(tenant_stmt)
result = await self.db.execute(tenant_stmt)
tenant = result.scalar_one_or_none()
if not tenant:
raise CustomException(msg="租户不存在")