mirror of
https://github.com/EstrellaXD/Auto_Bangumi.git
synced 2026-04-13 18:11:03 +08:00
- Add passkey login as alternative authentication method - Support multiple passkeys per user with custom names - Backend: WebAuthn service, auth strategy pattern, API endpoints - Frontend: passkey management UI in settings, login option - Fix: convert downloader check from sync requests to async httpx to prevent blocking the event loop when downloader unavailable Co-Authored-By: Claude Opus 4.5 <noreply@anthropic.com>
76 lines
1.9 KiB
Python
76 lines
1.9 KiB
Python
"""
|
|
WebAuthn Passkey 数据模型
|
|
"""
|
|
from datetime import datetime
|
|
from typing import Optional
|
|
|
|
from pydantic import BaseModel
|
|
from sqlmodel import Field, SQLModel
|
|
|
|
|
|
class Passkey(SQLModel, table=True):
|
|
"""存储 WebAuthn 凭证的数据库模型"""
|
|
|
|
__tablename__ = "passkey"
|
|
|
|
id: int = Field(default=None, primary_key=True)
|
|
user_id: int = Field(foreign_key="user.id", index=True)
|
|
|
|
# 用户友好的名称 (e.g., "iPhone 15", "MacBook Pro")
|
|
name: str = Field(min_length=1, max_length=64)
|
|
|
|
# WebAuthn 核心字段
|
|
credential_id: str = Field(unique=True, index=True) # Base64URL encoded
|
|
public_key: str # CBOR encoded public key, Base64 stored
|
|
sign_count: int = Field(default=0) # 防止克隆攻击
|
|
|
|
# 可选的设备信息
|
|
aaguid: Optional[str] = None # Authenticator AAGUID
|
|
transports: Optional[str] = None # JSON array: ["usb", "nfc", "ble", "internal"]
|
|
|
|
# 审计字段
|
|
created_at: datetime = Field(default_factory=datetime.utcnow)
|
|
last_used_at: Optional[datetime] = None
|
|
|
|
# 备份状态 (是否为多设备凭证,如 iCloud Keychain)
|
|
backup_eligible: bool = Field(default=False)
|
|
backup_state: bool = Field(default=False)
|
|
|
|
|
|
class PasskeyCreate(BaseModel):
|
|
"""创建 Passkey 的请求模型"""
|
|
|
|
name: str = Field(min_length=1, max_length=64)
|
|
# 注册完成后的 WebAuthn 响应
|
|
attestation_response: dict
|
|
|
|
|
|
class PasskeyList(BaseModel):
|
|
"""返回给前端的 Passkey 列表(不含敏感数据)"""
|
|
|
|
id: int
|
|
name: str
|
|
created_at: datetime
|
|
last_used_at: Optional[datetime]
|
|
backup_eligible: bool
|
|
aaguid: Optional[str]
|
|
|
|
|
|
class PasskeyDelete(BaseModel):
|
|
"""删除 Passkey 请求"""
|
|
|
|
passkey_id: int
|
|
|
|
|
|
class PasskeyAuthStart(BaseModel):
|
|
"""Passkey 认证开始请求"""
|
|
|
|
username: str
|
|
|
|
|
|
class PasskeyAuthFinish(BaseModel):
|
|
"""Passkey 认证完成请求"""
|
|
|
|
username: str
|
|
credential: dict
|