feat: 添加密码重置功能
- 后端: 新增 POST /auth/reset-password 端点(邮箱+验证码+新密码) - 后端: 新增 ResetPasswordRequest schema - 前端: 新增 /forgot-password 页面(分步骤:输入邮箱→验证码+新密码→完成) - 前端: 登录页添加"忘记密码?"链接 Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
co-authored by
Claude Opus 4.6
parent
45c6c034e0
commit
3a6e25b5b1
@@ -13,6 +13,7 @@ from app.schemas.auth import (
|
||||
LoginResponse,
|
||||
RefreshTokenRequest,
|
||||
RefreshTokenResponse,
|
||||
ResetPasswordRequest,
|
||||
SendEmailCodeRequest,
|
||||
UserResponse,
|
||||
)
|
||||
@@ -27,6 +28,7 @@ from app.services.auth import (
|
||||
update_refresh_token,
|
||||
decode_token,
|
||||
get_user_organization_info,
|
||||
hash_password,
|
||||
)
|
||||
from app.services.verification import generate_code, verify_code
|
||||
from app.services.email import send_verification_email
|
||||
@@ -323,6 +325,47 @@ async def refresh_token(
|
||||
return RefreshTokenResponse(access_token=access_token)
|
||||
|
||||
|
||||
@router.post("/reset-password")
|
||||
async def reset_password(
|
||||
request: ResetPasswordRequest,
|
||||
req: Request,
|
||||
db: AsyncSession = Depends(get_db),
|
||||
):
|
||||
"""
|
||||
重置密码
|
||||
|
||||
- 需要先调用 /auth/send-code (purpose=reset_password) 获取验证码
|
||||
- 验证码正确后设置新密码
|
||||
"""
|
||||
# 验证验证码
|
||||
if not verify_code(request.email, request.email_code, "reset_password"):
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="验证码错误或已过期",
|
||||
)
|
||||
|
||||
# 查找用户
|
||||
user = await get_user_by_email(db, request.email)
|
||||
if not user:
|
||||
raise HTTPException(
|
||||
status_code=status.HTTP_400_BAD_REQUEST,
|
||||
detail="该邮箱未注册",
|
||||
)
|
||||
|
||||
# 更新密码
|
||||
user.password_hash = hash_password(request.new_password)
|
||||
|
||||
# 审计日志
|
||||
await log_action(
|
||||
db, "reset_password", "user", user.id, user.id,
|
||||
user.name, user.role.value,
|
||||
ip_address=req.client.host if req.client else None,
|
||||
)
|
||||
|
||||
await db.commit()
|
||||
return {"message": "密码已重置,请使用新密码登录"}
|
||||
|
||||
|
||||
@router.post("/logout")
|
||||
async def logout(
|
||||
req: Request,
|
||||
|
||||
@@ -81,6 +81,22 @@ class BindEmailRequest(BaseModel):
|
||||
password: str = Field(..., min_length=6, max_length=128)
|
||||
|
||||
|
||||
class ResetPasswordRequest(BaseModel):
|
||||
"""重置密码请求(通过邮箱验证码)"""
|
||||
email: EmailStr
|
||||
email_code: str = Field(..., min_length=4, max_length=8)
|
||||
new_password: str = Field(..., min_length=6, max_length=128)
|
||||
|
||||
class Config:
|
||||
json_schema_extra = {
|
||||
"example": {
|
||||
"email": "user@example.com",
|
||||
"email_code": "123456",
|
||||
"new_password": "newpassword123"
|
||||
}
|
||||
}
|
||||
|
||||
|
||||
class ChangePasswordRequest(BaseModel):
|
||||
"""修改密码请求"""
|
||||
old_password: str
|
||||
|
||||
Reference in New Issue
Block a user