Files
server-core/app/api/schemas/auth.py
T
Pine f697fdad37 feat(auth): 统一账号绑定/解绑 + 按手机号自动合并(同一账号不新建)
- merge_accounts(keeper,absorbed): 身份字段继承、user_identities改挂、audit_logs/任务归属改指keeper、absorbed级联删除(防FK阻断)
- POST /auth/bind-phone(验证码,手机号被占用→按手机号合并成keeper并返新令牌); POST /auth/unbind(至少要留一种登录方式); wx-phone 改走合并
- profile 加 wxBound/wxMiniBound; schemas BindPhoneRequest/UnbindRequest
2026-08-26 12:15:22 +08:00

165 lines
5.3 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.
from pydantic import BaseModel, Field
class IdentityInfo(BaseModel):
"""账号绑定的一端口身份摘要(登录/选择身份时返回)。"""
id: str
port: str = "opc"
role: str = "opc_member"
sub_role: str | None = None
name: str = ""
org_id: str | None = None
region_id: str | None = None
org_name: str | None = None
region_name: str | None = None
status: str = "active"
class LoginRequest(BaseModel):
username: str
password: str
expires_in: int | None = Field(
default=None,
description="令牌有效期(秒),-1/0 表示永久,省略为 7 天",
)
class RegisterRequest(BaseModel):
username: str
password: str
expires_in: int | None = Field(
default=None,
description="令牌有效期(秒),-1/0 表示永久,省略为 7 天",
)
class UpdateProfileRequest(BaseModel):
"""更新资料/凭据。``current_password`` 仅在修改用户名/密码时校验。"""
current_password: str = ""
new_username: str | None = None
new_password: str | None = None
expires_in: int | None = None
# 演示用户资料字段(账户管理页可编辑)
nickname: str | None = None
# 小程序契约字段(name→nicknamestatus→opc_statustopics→JSON 列表)
name: str | None = None
status: str | None = None
topics: list[str] | None = None
account: str | None = None
company: str | None = None
room: str | None = None
avatar: str | None = None
company_avatar: str | None = None
class RevokeTokenRequest(BaseModel):
token: str | None = Field(
default=None,
description="要吊销的令牌;省略则吊销当前令牌",
)
class AuthStatusResponse(BaseModel):
enabled: bool
has_users: bool
login_modes: list[str] = ["password", "phone"] # password/phone/wechat/miniprogram(四种)
wechat_login: bool = False # 小程序扫码(code2session)
wx_qr: bool = False # 微信开放平台扫码(OAuth)
class VerifyResponse(BaseModel):
valid: bool
username: str = ""
class UserProfile(BaseModel):
"""用户资料(登录/me/update-profile 均返回该结构)。"""
username: str = ""
nickname: str = ""
name: str = "" # 别名 = nickname(小程序契约:显示名 / 报名资料姓名)
phone: str = "" # 已绑定手机号
phoneBound: bool = False # 是否已绑手机(小程序「已绑定手机」徽标/绑定门槛)
account: str = ""
company: str = ""
room: str = ""
avatar: str = ""
company_avatar: str = ""
# RBAC(登录/me 返回;update-profile 不重签时不返回权限明细)
role: str = "opc_member"
sub_role: str | None = None
org_id: str | None = None
region_id: str | None = None
permissions: list[str] = Field(default_factory=list)
scope_region_ids: list[str] = Field(default_factory=list)
# 当前生效的端口身份(多身份绑定)
identity_id: str | None = None
port: str | None = None
identity_name: str = ""
class LoginResponse(UserProfile):
"""登录/注册成功后的响应:资料 + 新令牌。"""
token: str = ""
identities: list[IdentityInfo] = Field(default_factory=list)
class ProfileResponse(UserProfile):
"""update-profile 成功后的响应;修改凭据时附带新令牌。"""
token: str = ""
identities: list[IdentityInfo] = Field(default_factory=list)
class SelectIdentityRequest(BaseModel):
"""切换到指定端口身份:为新身份签发令牌。"""
identity_id: str
# ---------------------------------------------------------------------------
# 统一登录(手机验证码 / 微信)—— 六端登录归一
# ---------------------------------------------------------------------------
class SendCodeRequest(BaseModel):
phone: str = Field(description="11 位手机号(作为登录账号)")
class SendCodeResponse(BaseModel):
sent: bool = True
message: str = "验证码已发送"
# 非空时表示走 stub 直发(仅开发/联调可见)
stub_code: str | None = None
class PhoneLoginRequest(BaseModel):
phone: str
code: str = Field(description="手机号接收到的 6 位验证码")
class WxLoginRequest(BaseModel):
code: str = Field(description="wx.login 返回的 code(未配置 appid 时当作 openid 直通)")
nickName: str = ""
avatarUrl: str = ""
class WxPhoneRequest(BaseModel):
openid: str
phone: str = Field(description="待补绑的手机号")
code: str = Field(description="手机号接收到的验证码")
class MpQrConfirmRequest(BaseModel):
"""小程序扫码登录确认(小程序内 wx.login 后调用)。"""
scene: str = Field(description="web/桌面端 /auth/mp-qr/start 返回的场景")
code: str = Field(description="wx.login 返回的 code")
class BindPhoneRequest(BaseModel):
"""当前账号绑定手机号(验证码;若该手机号已被其它账号占用则按手机号合并)。"""
phone: str
code: str = Field(description="发送到该手机号的验证码")
class UnbindRequest(BaseModel):
"""解除已绑定的登录方式(保留至少一种登录方式)。"""
type: str = Field(description="phone | wx | wx_mini")
# RBAC 管理请求/响应