refactor: 移除多租户相关代码,重构为单租户架构

此次提交进行了大规模的架构重构:
1.  移除所有平台租户相关模块和代码,包括租户管理、套餐、订单、发票等功能
2.  将菜单模块从platform迁移到system模块,统一系统功能入口
3.  移除租户隔离相关的模型混入、中间件和配置
4.  简化文件上传、SSE事件总线、定时任务等模块的租户逻辑
5.  重构所有业务schema和模型,移除租户相关字段和关联
6.  清理初始化脚本、模板和常量中的租户相关代码
7.  简化认证和权限控制逻辑,移除数据范围检查相关代码
This commit is contained in:
zhangtao
2026-07-16 23:22:45 +08:00
parent f74b5f277e
commit a222cd9e43
119 changed files with 421 additions and 7145 deletions
@@ -4,8 +4,6 @@ from typing import Annotated
from fastapi import APIRouter, BackgroundTasks, Body, Depends, Path, Query, Request, status
from fastapi.responses import JSONResponse, RedirectResponse
from fastapi_cache import FastAPICache
from fastapi_cache.decorator import cache
from redis.asyncio.client import Redis
from sqlalchemy.ext.asyncio import AsyncSession
@@ -31,78 +29,26 @@ from .oauth_service import (
)
from .schema import (
CaptchaOutSchema,
EnterPlatformOutSchema,
ImpersonateOutSchema,
ImpersonateSchema,
LoginWithTenantsSchema,
SelectTenantOutSchema,
SelectTenantSchema,
LoginOutSchema,
SliderCompleteOutSchema,
SliderCompleteSchema,
TenantLookupOutSchema,
TenantOptionSchema,
TenantRegisterOutSchema,
TenantRegisterSchema,
)
from .service import (
CaptchaService,
LoginService,
TenantLookupService,
TenantRegisterService,
)
AuthRouter = APIRouter(route_class=OperationLogRoute, prefix="/auth", tags=["认证授权"])
_AUTH_TENANTS_NS = "auth_tenants"
@AuthRouter.get("/tenant/{code}", summary="通过编码查询租户", response_model=ResponseSchema[TenantLookupOutSchema])
async def lookup_tenant_controller(
db: Annotated[AsyncSession, Depends(db_getter)],
code: Annotated[str, Path(description="租户编码")],
) -> JSONResponse:
"""根据租户编码查询租户信息(用于登录页自动加载租户品牌配置)"""
data = await TenantLookupService.lookup_by_code(db=db, code=code)
return SuccessResponse(data=data, msg="查询成功")
@AuthRouter.get("/tenant-by-domain", summary="通过域名查询租户", response_model=ResponseSchema[TenantLookupOutSchema])
async def lookup_tenant_by_domain_controller(
db: Annotated[AsyncSession, Depends(db_getter)],
domain: Annotated[str, Query(description="域名(如 tenant.example.com")],
) -> JSONResponse:
"""根据域名查询租户信息(用于登录页通过访问域名自动识别租户品牌)"""
data = await TenantLookupService.lookup_by_domain(db=db, domain=domain)
return SuccessResponse(data=data, msg="查询成功")
@AuthRouter.get("/tenant-options", summary="获取所有租户选项(登录页下拉选择)", response_model=ResponseSchema[list[TenantOptionSchema]])
async def get_tenant_options_controller(
db: Annotated[AsyncSession, Depends(db_getter)],
) -> JSONResponse:
"""获取所有活跃租户下拉选项"""
data = await TenantLookupService.list_options(db=db)
return SuccessResponse(data=data, msg="查询成功")
@AuthRouter.get("/tenant-search", summary="搜索租户(按编码/名称模糊匹配)", response_model=ResponseSchema[list[TenantOptionSchema]])
async def search_tenant_controller(
db: Annotated[AsyncSession, Depends(db_getter)],
q: Annotated[str, Query(description="搜索关键字")],
) -> JSONResponse:
"""模糊搜索租户"""
data = await TenantLookupService.search(db=db, q=q)
return SuccessResponse(data=data, msg="查询成功")
@AuthRouter.post("/login", summary="登录", response_model=LoginWithTenantsSchema)
@AuthRouter.post("/login", summary="登录", response_model=LoginOutSchema)
async def login_for_access_token_controller(
request: Request,
background_tasks: BackgroundTasks,
redis: Annotated[Redis, Depends(redis_getter)],
db: Annotated[AsyncSession, Depends(db_getter)],
login_form: Annotated[CustomOAuth2PasswordRequestForm, Depends()],
) -> JSONResponse | LoginWithTenantsSchema:
) -> JSONResponse | LoginOutSchema:
login_result = await LoginService.authenticate_user(request=request, redis=redis, login_form=login_form, db=db, background_tasks=background_tasks)
logger.info(f"用户{login_form.username}登录成功")
@@ -150,55 +96,6 @@ async def logout_controller(
return ErrorResponse(msg="退出失败")
@AuthRouter.post("/select-tenant", summary="选择租户", response_model=ResponseSchema[SelectTenantOutSchema], dependencies=[Depends(get_current_user)])
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, db).select_tenant(request=request, redis=redis, tenant_id=data.tenant_id)
await FastAPICache.clear(namespace=_AUTH_TENANTS_NS)
return SuccessResponse(data=result, msg="租户切换成功")
@AuthRouter.post("/enter-platform", summary="进入平台管理模式", response_model=ResponseSchema[EnterPlatformOutSchema], dependencies=[Depends(get_current_user)])
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, db).enter_platform(request=request, redis=redis)
await FastAPICache.clear(namespace=_AUTH_TENANTS_NS)
return SuccessResponse(data=result, msg="已返回平台管理模式")
@AuthRouter.get("/tenants", summary="获取可选租户列表", response_model=ResponseSchema[list[TenantOptionSchema]], dependencies=[Depends(get_current_user)])
@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, db)
tenants = await service.get_user_tenants()
return SuccessResponse(data=tenants, msg="获取租户列表成功")
@AuthRouter.post("/impersonate", summary="平台管理员代签入", response_model=ResponseSchema[ImpersonateOutSchema], dependencies=[Depends(get_current_user)])
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, db).impersonate(request=request, redis=redis, tenant_id=data.tenant_id)
await FastAPICache.clear(namespace=_AUTH_TENANTS_NS)
return SuccessResponse(data=result, msg="代签入成功")
@AuthRouter.get("/oauth/{provider}/login", summary="第三方OAuth跳转")
async def oauth_login_redirect_controller(
request: Request,
@@ -281,19 +178,3 @@ async def oauth_callback_controller(
except CustomException as e:
fe = await resolve_frontend()
return RedirectContentResponse(url=oauth_service_error_redirect(fe, e.msg), status_code=302)
@AuthRouter.post("/tenant/register", status_code=status.HTTP_201_CREATED, summary="租户自助注册", response_model=ResponseSchema[TenantRegisterOutSchema])
async def tenant_register_controller(
db: Annotated[AsyncSession, Depends(db_getter)],
data: Annotated[TenantRegisterSchema, Body(description="租户注册参数")],
) -> JSONResponse:
result = await TenantRegisterService.register(
db=db,
username=data.username,
password=data.password,
email=data.email,
tenant_name=data.tenant_name,
)
logger.info(f"新租户注册: username={data.username} tenant={result.tenant_name}")
return SuccessResponse(data=result, msg=result.message)