feat: add PATCH /user/settings/password endpoint for changing password
All checks were successful
Test / test (push) Successful in 1m43s

Register the fixed /password route before the wildcard /{option} to
prevent FastAPI from matching it as a path parameter.

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
This commit is contained in:
2026-02-14 15:11:56 +08:00
parent ccadfe57cd
commit 71883d32c0
3 changed files with 49 additions and 0 deletions

View File

@@ -11,6 +11,7 @@ from sqlmodels import (
BUILTIN_DEFAULT_COLORS, ThemePreset, UserThemeUpdateRequest,
SettingOption, UserSettingUpdateRequest,
AuthIdentity, AuthIdentityResponse, AuthProviderType, BindIdentityRequest,
ChangePasswordRequest,
AuthnDetailResponse, AuthnRenameRequest,
)
from sqlmodels.color import ThemeColorsBase
@@ -226,6 +227,43 @@ async def router_user_settings_theme(
await user.save(session)
@user_settings_router.patch(
path='/password',
summary='修改密码',
status_code=status.HTTP_204_NO_CONTENT,
)
async def router_user_settings_change_password(
session: SessionDep,
user: Annotated[sqlmodels.user.User, Depends(auth_required)],
request: ChangePasswordRequest,
) -> None:
"""
修改当前用户密码
请求体:
- old_password: 当前密码
- new_password: 新密码(至少 8 位)
错误处理:
- 400: 用户没有邮箱密码认证身份
- 403: 当前密码错误
"""
email_identity: AuthIdentity | None = await AuthIdentity.get(
session,
(AuthIdentity.user_id == user.id)
& (AuthIdentity.provider == AuthProviderType.EMAIL_PASSWORD),
)
if not email_identity or not email_identity.credential:
http_exceptions.raise_bad_request("未找到邮箱密码认证身份")
verify_result = Password.verify(email_identity.credential, request.old_password)
if verify_result == PasswordStatus.INVALID:
http_exceptions.raise_forbidden("当前密码错误")
email_identity.credential = Password.hash(request.new_password)
await email_identity.save(session)
@user_settings_router.patch(
path='/{option}',
summary='更新用户设定',

View File

@@ -3,6 +3,7 @@ from .auth_identity import (
AuthIdentityResponse,
AuthProviderType,
BindIdentityRequest,
ChangePasswordRequest,
)
from .user import (
BatchDeleteRequest,

View File

@@ -81,6 +81,16 @@ class BindIdentityRequest(SQLModelBase):
"""OAuth 回调地址"""
class ChangePasswordRequest(SQLModelBase):
"""修改密码请求 DTO"""
old_password: str = Field(min_length=1)
"""当前密码"""
new_password: str = Field(min_length=8, max_length=128)
"""新密码(至少 8 位)"""
# ==================== 数据库模型 ====================
class AuthIdentity(SQLModelBase, UUIDTableBaseMixin):