Files
disknext/sqlmodels/auth_identity.py
于小丘 6c96c43bea
Some checks failed
Test / test (push) Failing after 3m47s
refactor: 统一 sqlmodel_ext 用法至官方推荐模式
- 替换 Field(max_length=X) 为 StrX/TextX 类型别名(21 个 sqlmodels 文件)
- 替换 get + 404 检查为 get_exist_one()(17 个路由文件,约 50 处)
- 替换 save + session.refresh 为 save(load=...)
- 替换 session.add + commit 为 save()(dav/provider.py)
- 更新所有依赖至最新版本

Co-Authored-By: Claude Opus 4.6 <noreply@anthropic.com>
2026-03-09 11:13:16 +08:00

149 lines
3.5 KiB
Python
Raw Blame History

This file contains ambiguous Unicode characters
This file contains Unicode characters that might be confused with other characters. If you think that this is intentional, you can safely ignore this warning. Use the Escape button to reveal them.
"""
认证身份模块
一个用户可拥有多种登录方式邮箱密码、OAuth、Passkey、Magic Link 等)。
AuthIdentity 表存储每种认证方式的凭证信息。
"""
from enum import StrEnum
from typing import TYPE_CHECKING
from uuid import UUID
from sqlmodel import Field, Relationship, UniqueConstraint
from sqlmodel_ext import SQLModelBase, UUIDTableBaseMixin, Str100, Str128, Str255, Text1024
if TYPE_CHECKING:
from .user import User
class AuthProviderType(StrEnum):
"""认证提供者类型"""
EMAIL_PASSWORD = "email_password"
"""邮箱+密码"""
PHONE_SMS = "phone_sms"
"""手机号+短信验证码(预留)"""
GITHUB = "github"
"""GitHub OAuth"""
QQ = "qq"
"""QQ OAuth"""
PASSKEY = "passkey"
"""Passkey/WebAuthn"""
MAGIC_LINK = "magic_link"
"""邮箱 Magic Link"""
# ==================== DTO 模型 ====================
class AuthIdentityResponse(SQLModelBase):
"""认证身份响应 DTO列表展示用"""
id: UUID
"""身份UUID"""
provider: AuthProviderType
"""提供者类型"""
identifier: str
"""标识符(邮箱/手机号/OAuth openid"""
display_name: str | None = None
"""显示名称OAuth 昵称等)"""
avatar_url: str | None = None
"""头像 URL"""
is_primary: bool = False
"""是否主要身份"""
is_verified: bool = False
"""是否已验证"""
class BindIdentityRequest(SQLModelBase):
"""绑定认证身份请求 DTO"""
provider: AuthProviderType
"""提供者类型"""
identifier: str
"""标识符(邮箱/手机号/OAuth code"""
credential: str | None = None
"""凭证(密码、验证码等)"""
redirect_uri: str | None = None
"""OAuth 回调地址"""
class ChangePasswordRequest(SQLModelBase):
"""修改密码请求 DTO"""
old_password: str = Field(min_length=1)
"""当前密码"""
new_password: Str128 = Field(min_length=8)
"""新密码(至少 8 位)"""
# ==================== 数据库模型 ====================
class AuthIdentity(SQLModelBase, UUIDTableBaseMixin):
"""用户认证身份 — 一个用户可以有多种登录方式"""
__table_args__ = (
UniqueConstraint("provider", "identifier", name="uq_auth_identity_provider_identifier"),
)
provider: AuthProviderType = Field(index=True)
"""提供者类型"""
identifier: Str255 = Field(index=True)
"""标识符(邮箱/手机号/OAuth openid"""
credential: Text1024 | None = None
"""凭证Argon2 哈希密码 / null"""
display_name: Str100 | None = None
"""OAuth 昵称"""
avatar_url: str | None = Field(default=None, max_length=512)
"""OAuth 头像 URL"""
extra_data: str | None = None
"""JSON 附加数据2FA secret、OAuth refresh_token 等)"""
is_primary: bool = False
"""是否主要身份"""
is_verified: bool = False
"""是否已验证"""
# 外键
user_id: UUID = Field(
foreign_key="user.id",
index=True,
ondelete="CASCADE",
)
"""所属用户UUID"""
# 关系
user: "User" = Relationship(back_populates="auth_identities")
def to_response(self) -> AuthIdentityResponse:
"""转换为响应 DTO"""
return AuthIdentityResponse(
id=self.id,
provider=self.provider,
identifier=self.identifier,
display_name=self.display_name,
avatar_url=self.avatar_url,
is_primary=self.is_primary,
is_verified=self.is_verified,
)