mirror of
https://github.com/fastapiadmin/FastapiAdmin.git
synced 2026-09-21 20:55:14 +00:00
refactor: 统一项目中状态字段类型为数字类型
这是一个大规模的类型对齐优化: 1. 将多处字符串类型的status字段统一改为数字类型,包括前后端接口定义、数据模型、页面组件 2. 重构编排节点相关的命名和注释,统一改为"节点类型"替代"编排节点类型" 3. 移除了过时的忘记密码相关接口和模板代码 4. 优化搜索栏组件,支持展开仅显示次要字段 5. 调整部分接口参数和路由逻辑,对齐前后端参数格式
This commit is contained in:
@@ -37,9 +37,7 @@ from .schema import (
|
||||
AutoLoginTokenSchema,
|
||||
AutoLoginUserSchema,
|
||||
CaptchaOutSchema,
|
||||
ForgotPasswordSchema,
|
||||
LoginWithTenantsSchema,
|
||||
ResetPasswordWithTokenSchema,
|
||||
SelectTenantOutSchema,
|
||||
SelectTenantSchema,
|
||||
TenantOptionSchema,
|
||||
@@ -50,7 +48,6 @@ from .service import (
|
||||
AutoLoginService,
|
||||
CaptchaService,
|
||||
LoginService,
|
||||
PasswordResetService,
|
||||
TenantRegisterService,
|
||||
)
|
||||
|
||||
@@ -314,29 +311,4 @@ async def tenant_register_controller(
|
||||
return SuccessResponse(data=result, msg=result.message)
|
||||
|
||||
|
||||
@AuthRouter.post(
|
||||
"/forgot-password",
|
||||
summary="忘记密码",
|
||||
response_model=ResponseSchema[str],
|
||||
)
|
||||
async def forgot_password_controller(
|
||||
data: ForgotPasswordSchema,
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
db: Annotated[AsyncSession, Depends(db_getter)],
|
||||
) -> JSONResponse:
|
||||
msg = await PasswordResetService.forgot_password(redis=redis, db=db, email=data.email)
|
||||
return SuccessResponse(data=msg, msg="邮件已发送")
|
||||
|
||||
|
||||
@AuthRouter.post(
|
||||
"/reset-password",
|
||||
summary="重置密码",
|
||||
response_model=ResponseSchema[str],
|
||||
)
|
||||
async def reset_password_controller(
|
||||
data: ResetPasswordWithTokenSchema,
|
||||
redis: Annotated[Redis, Depends(redis_getter)],
|
||||
db: Annotated[AsyncSession, Depends(db_getter)],
|
||||
) -> JSONResponse:
|
||||
msg = await PasswordResetService.reset_password_with_token(redis=redis, db=db, token=data.token, new_password=data.new_password)
|
||||
return SuccessResponse(data=msg, msg="密码已重置")
|
||||
|
||||
@@ -86,16 +86,3 @@ class TenantRegisterOutSchema(BaseModel):
|
||||
package: str | None = Field(default=None, description="开通套餐")
|
||||
trial_end: str = Field(..., description="试用到期日")
|
||||
message: str = Field(default="注册成功", description="提示信息")
|
||||
|
||||
|
||||
class ForgotPasswordSchema(BaseModel):
|
||||
"""忘记密码:提交邮箱,接收重置邮件"""
|
||||
|
||||
email: str = Field(..., max_length=128, description="注册时使用的邮箱")
|
||||
|
||||
|
||||
class ResetPasswordWithTokenSchema(BaseModel):
|
||||
"""通过邮件链接重置密码"""
|
||||
|
||||
token: str = Field(..., min_length=1, description="密码重置令牌")
|
||||
new_password: str = Field(..., min_length=6, max_length=128, description="新密码")
|
||||
|
||||
@@ -1,6 +1,5 @@
|
||||
|
||||
import json
|
||||
import secrets
|
||||
import uuid
|
||||
from datetime import datetime, timedelta
|
||||
from typing import NewType
|
||||
@@ -847,104 +846,3 @@ class TenantRegisterService:
|
||||
body_html=html_body,
|
||||
)
|
||||
logger.info(f"欢迎邮件已发送至 {to_email}")
|
||||
|
||||
|
||||
class PasswordResetService:
|
||||
"""PRD §4.6 忘记密码:邮箱重置令牌 + 密码更新"""
|
||||
|
||||
RESET_TOKEN_PREFIX = "pwd_reset:"
|
||||
TOKEN_EXPIRE_SECONDS = 1800 # 30 分钟
|
||||
|
||||
@classmethod
|
||||
async def forgot_password(cls, redis: Redis, db: AsyncSession, email: str) -> str:
|
||||
"""忘记密码:根据邮箱查找用户,生成重置令牌并尝试发送邮件。"""
|
||||
from sqlalchemy import select
|
||||
|
||||
from app.api.v1.module_system.user.model import UserModel
|
||||
|
||||
stmt = select(UserModel).where(
|
||||
UserModel.email == email,
|
||||
UserModel.is_deleted.is_(False),
|
||||
)
|
||||
result = await db.execute(stmt)
|
||||
user = result.scalar_one_or_none()
|
||||
|
||||
if not user:
|
||||
logger.info(f"忘记密码:邮箱 {email} 未注册,静默返回")
|
||||
return "若邮箱已注册,重置邮件已发送"
|
||||
|
||||
token = secrets.token_urlsafe(32)
|
||||
key = f"{cls.RESET_TOKEN_PREFIX}{token}"
|
||||
await RedisCURD(redis).set(key=key, value=str(user.id), expire=cls.TOKEN_EXPIRE_SECONDS)
|
||||
|
||||
try:
|
||||
await cls._send_reset_email(email, user.username, token)
|
||||
except Exception:
|
||||
logger.warning(f"密码重置邮件发送失败: {email}")
|
||||
|
||||
return "若邮箱已注册,重置邮件已发送"
|
||||
|
||||
@classmethod
|
||||
async def reset_password_with_token(cls, redis: Redis, db: AsyncSession, token: str, new_password: str) -> str:
|
||||
"""使用令牌重置密码。校验令牌 → 更新密码 → 删除令牌。"""
|
||||
from app.api.v1.module_system.user.model import UserModel
|
||||
|
||||
key = f"{cls.RESET_TOKEN_PREFIX}{token}"
|
||||
user_id_str = await RedisCURD(redis).get(key)
|
||||
|
||||
if not user_id_str:
|
||||
raise CustomException(msg="重置链接已失效,请重新申请")
|
||||
|
||||
try:
|
||||
user_id = int(user_id_str)
|
||||
except (ValueError, TypeError):
|
||||
await RedisCURD(redis).delete(key)
|
||||
raise CustomException(msg="无效的重置链接")
|
||||
|
||||
user = await db.get(UserModel, user_id)
|
||||
if not user or user.is_deleted:
|
||||
await RedisCURD(redis).delete(key)
|
||||
raise CustomException(msg="用户不存在")
|
||||
|
||||
user.password = PwdUtil.hash_password(new_password)
|
||||
await db.commit()
|
||||
await RedisCURD(redis).delete(key)
|
||||
|
||||
logger.info(f"用户 {user.username}(id={user_id}) 密码已重置")
|
||||
return "密码重置成功,请使用新密码登录"
|
||||
|
||||
@classmethod
|
||||
async def _send_reset_email(cls, to_email: str, username: str, token: str) -> None:
|
||||
"""发送密码重置邮件。"""
|
||||
from app.api.v1.module_platform.email.crud import EmailConfigCRUD
|
||||
from app.core.base_schema import AuthSchema
|
||||
from app.core.database import async_db_session
|
||||
from app.utils.email_util import render_template_file, send_email
|
||||
|
||||
async with async_db_session() as _db:
|
||||
cfg = await EmailConfigCRUD(AuthSchema(db=_db, check_data_scope=False)).get_active_default()
|
||||
|
||||
if not cfg:
|
||||
logger.info("无可用 SMTP 配置,跳过重置邮件")
|
||||
return
|
||||
|
||||
reset_url = f"{getattr(settings, 'SITE_URL', '')}/reset-password?token={token}"
|
||||
html_body = render_template_file("emails/reset_password.jinja2", {
|
||||
"username": username,
|
||||
"reset_url": reset_url,
|
||||
"expire_minutes": cls.TOKEN_EXPIRE_SECONDS // 60,
|
||||
})
|
||||
|
||||
await send_email(
|
||||
smtp_host=cfg.smtp_host,
|
||||
smtp_port=cfg.smtp_port,
|
||||
smtp_user=cfg.smtp_user,
|
||||
smtp_password=cfg.smtp_password,
|
||||
use_tls=cfg.use_tls,
|
||||
from_name=cfg.from_name,
|
||||
to_email=to_email,
|
||||
to_name=username,
|
||||
subject="密码重置 - FastapiAdmin",
|
||||
body_html=html_body,
|
||||
)
|
||||
logger.info(f"密码重置邮件已发送至 {to_email}")
|
||||
|
||||
Reference in New Issue
Block a user