mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-23 13:13:09 +00:00
refactor: 重构项目模块结构与代码细节优化
1. 调整后端模块路由与插件文件结构,迁移部分模块代码至api/v1目录 2. 优化代码注释格式与文档字符串,简化冗余代码 3. 添加监控仪表盘、工单评论等新模块功能 4. 修复前端部分组件交互逻辑与类型定义 5. 清理冗余的初始化数据与废弃配置文件 6. 新增租户注册表单字段与国际化支持 7. 优化HTTP请求拦截器与快捷键功能
This commit is contained in:
@@ -2,7 +2,7 @@ import json
|
||||
import secrets
|
||||
from typing import Annotated
|
||||
|
||||
from fastapi import APIRouter, BackgroundTasks, Body, Depends, Path, Query, Request
|
||||
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
|
||||
@@ -14,8 +14,6 @@ from app.config.setting import settings
|
||||
from app.core.base_schema import (
|
||||
AuthSchema,
|
||||
JWTOutSchema,
|
||||
LogoutPayloadSchema,
|
||||
RefreshTokenPayloadSchema,
|
||||
)
|
||||
from app.core.dependencies import db_getter, get_current_user, redis_getter
|
||||
from app.core.exceptions import CustomException
|
||||
@@ -26,6 +24,7 @@ from app.core.security import CustomOAuth2PasswordRequestForm
|
||||
|
||||
from .oauth_service import (
|
||||
STATE_PREFIX,
|
||||
OAuthProvider,
|
||||
_callback_url,
|
||||
build_authorize_url,
|
||||
complete_oauth_login,
|
||||
@@ -34,20 +33,22 @@ from .oauth_service import (
|
||||
save_oauth_state,
|
||||
)
|
||||
from .schema import (
|
||||
AutoLoginTokenSchema,
|
||||
AutoLoginUserSchema,
|
||||
CaptchaOutSchema,
|
||||
EnterPlatformOutSchema,
|
||||
ImpersonateOutSchema,
|
||||
ImpersonateSchema,
|
||||
LoginWithTenantsSchema,
|
||||
SelectTenantOutSchema,
|
||||
SelectTenantSchema,
|
||||
TenantLookupOutSchema,
|
||||
TenantOptionSchema,
|
||||
TenantRegisterOutSchema,
|
||||
TenantRegisterSchema,
|
||||
)
|
||||
from .service import (
|
||||
AutoLoginService,
|
||||
CaptchaService,
|
||||
LoginService,
|
||||
TenantLookupService,
|
||||
TenantRegisterService,
|
||||
)
|
||||
|
||||
@@ -56,6 +57,26 @@ 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.post("/login", summary="登录", response_model=LoginWithTenantsSchema)
|
||||
async def login_for_access_token_controller(
|
||||
request: Request,
|
||||
@@ -63,10 +84,8 @@ async def login_for_access_token_controller(
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
db: Annotated[AsyncSession, Depends(db_getter)],
|
||||
login_form: Annotated[CustomOAuth2PasswordRequestForm, Depends()],
|
||||
) -> JSONResponse | dict:
|
||||
login_result = await LoginService.authenticate_user(
|
||||
request=request, redis=redis, login_form=login_form, db=db, background_tasks=background_tasks
|
||||
)
|
||||
) -> JSONResponse | LoginWithTenantsSchema:
|
||||
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}登录成功")
|
||||
|
||||
@@ -79,7 +98,7 @@ async def login_for_access_token_controller(
|
||||
async def get_new_token_controller(
|
||||
db: Annotated[AsyncSession, Depends(db_getter)],
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
payload: Annotated[RefreshTokenPayloadSchema, Body(description="刷新token参数")],
|
||||
payload: Annotated[str, Body(description="刷新token参数")],
|
||||
) -> JSONResponse:
|
||||
new_token = await LoginService.refresh_token(db=db, redis=redis, refresh_token=payload)
|
||||
return SuccessResponse(data=new_token, msg="刷新成功")
|
||||
@@ -96,7 +115,7 @@ async def get_captcha_for_login_controller(
|
||||
@AuthRouter.post("/logout", summary="退出登录", response_model=ResponseSchema[None], dependencies=[Depends(get_current_user)])
|
||||
async def logout_controller(
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
payload: Annotated[LogoutPayloadSchema, Body(description="退出登录参数")],
|
||||
payload: Annotated[str, Body(description="退出登录参数")],
|
||||
) -> JSONResponse:
|
||||
if await LoginService.logout(redis=redis, token=payload):
|
||||
logger.info("退出成功")
|
||||
@@ -104,40 +123,6 @@ async def logout_controller(
|
||||
return ErrorResponse(msg="退出失败")
|
||||
|
||||
|
||||
@AuthRouter.get("/auto-login/users", summary="获取免登录用户列表", response_model=ResponseSchema[list[AutoLoginUserSchema]])
|
||||
async def get_auto_login_users_controller(
|
||||
auth: Annotated[AuthSchema, Depends(get_current_user)],
|
||||
db: Annotated[AsyncSession, Depends(db_getter)],
|
||||
) -> JSONResponse:
|
||||
tenant_id = None if auth.user.is_superuser else auth.user.tenant_id
|
||||
users = await AutoLoginService.get_auto_login_users(db=db, tenant_id=tenant_id)
|
||||
return SuccessResponse(data=users, msg="获取成功")
|
||||
|
||||
|
||||
@AuthRouter.post("/auto-login/token", summary="获取免登录Token", response_model=ResponseSchema[AutoLoginTokenSchema])
|
||||
async def get_auto_login_token_controller(
|
||||
auth: Annotated[AuthSchema, Depends(get_current_user)],
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
db: Annotated[AsyncSession, Depends(db_getter)],
|
||||
user_id: Annotated[int, Body(description="用户ID")],
|
||||
) -> JSONResponse:
|
||||
tenant_id = None if auth.user.is_superuser else auth.user.tenant_id
|
||||
result = await AutoLoginService.create_auto_login_token(redis=redis, db=db, user_id=user_id, tenant_id=tenant_id)
|
||||
return SuccessResponse(data=result, msg="获取成功")
|
||||
|
||||
|
||||
@AuthRouter.post("/auto-login", summary="免登录", response_model=ResponseSchema[JWTOutSchema])
|
||||
async def auto_login_controller(
|
||||
request: Request,
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
db: Annotated[AsyncSession, Depends(db_getter)],
|
||||
token: Annotated[str, Body(description="免登录Token")],
|
||||
) -> JSONResponse:
|
||||
login_token = await AutoLoginService.auto_login(request=request, redis=redis, db=db, token=token)
|
||||
logger.info("用户免登录成功")
|
||||
return SuccessResponse(data=login_token, msg="登录成功")
|
||||
|
||||
|
||||
@AuthRouter.post("/select-tenant", summary="选择租户", response_model=ResponseSchema[SelectTenantOutSchema], dependencies=[Depends(get_current_user)])
|
||||
async def select_tenant_controller(
|
||||
request: Request,
|
||||
@@ -150,6 +135,17 @@ async def select_tenant_controller(
|
||||
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)],
|
||||
) -> JSONResponse:
|
||||
result = await LoginService(auth).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(
|
||||
@@ -160,11 +156,23 @@ async def get_user_tenants_controller(
|
||||
return SuccessResponse(data=tenants, msg="获取租户列表成功")
|
||||
|
||||
|
||||
@AuthRouter.get("/oauth/{provider}/login", summary="第三方OAuth跳转", response_model=RedirectContentResponse[None])
|
||||
@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)],
|
||||
data: Annotated[ImpersonateSchema, Body(description="代签入参数")],
|
||||
) -> JSONResponse:
|
||||
result = await LoginService(auth).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,
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
provider: Annotated[str, Path(description="wechat | qq | github | gitee")],
|
||||
provider: Annotated[OAuthProvider, Path(description="wechat | qq | github | gitee")],
|
||||
redirect_uri: Annotated[str | None, Query(description="OAuth 完成后浏览器回到的前端登录页完整 URL")] = None,
|
||||
) -> RedirectResponse:
|
||||
allowed = {"wechat", "qq", "github", "gitee"}
|
||||
@@ -197,12 +205,12 @@ async def oauth_login_redirect_controller(
|
||||
)
|
||||
|
||||
|
||||
@AuthRouter.get("/oauth/{provider}/callback", summary="第三方OAuth回调", include_in_schema=False, response_model=RedirectContentResponse[None])
|
||||
@AuthRouter.get("/oauth/{provider}/callback", summary="第三方OAuth回调", include_in_schema=False)
|
||||
async def oauth_callback_controller(
|
||||
request: Request,
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
db: Annotated[AsyncSession, Depends(db_getter)],
|
||||
provider: Annotated[str, Path(description="wechat | qq | github | gitee")],
|
||||
provider: Annotated[OAuthProvider, Path(description="wechat | qq | github | gitee")],
|
||||
code: Annotated[str | None, Query(description="OAuth 授权码")] = None,
|
||||
state: Annotated[str | None, Query(description="OAuth 状态参数")] = None,
|
||||
) -> RedirectResponse:
|
||||
@@ -244,7 +252,7 @@ async def oauth_callback_controller(
|
||||
return RedirectContentResponse(url=oauth_service_error_redirect(fe, e.msg), status_code=302)
|
||||
|
||||
|
||||
@AuthRouter.post("/tenant/register", summary="租户自助注册", response_model=ResponseSchema[TenantRegisterOutSchema])
|
||||
@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="租户注册参数")],
|
||||
|
||||
Reference in New Issue
Block a user