Files
story/openapi/operator-login.yaml
T
Codex Local bf1233d5df
ci / verify (push) Canceled after 0s
feat: expand companion platform, device controls, and memoir workflows
Add customer and operator login, BLE provisioning, device fleet controls, call memory, memoir generation, and refreshed family and maintenance portals. Include API contracts, migrations, firmware sources, tests, assets, and deployment documentation.
2026-10-08 10:06:44 +08:00

311 lines
14 KiB
YAML
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.
openapi: 3.1.0
info:
title: 管理端手机号登录
version: 1.1.0
paths:
/api/v1/web/operator/login/session:
get:
operationId: operatorLoginSession
summary: 初始化手机号登录页面
description: HTTPS,同源,不接受查询参数。签发 HttpOnly 登录 Cookie 和 CSRF token,20 分钟后过期,同一 Cookie 重载不会轮换 CSRF。短信不可用时仍可使用密码登录。
security: []
responses:
'200':
description: 页面状态;sms_enabled=false 不代表发送成功
headers:
Set-Cookie:
schema: { type: string }
content:
application/json:
schema:
type: object
required: [ok, data]
properties:
ok: { type: boolean }
data:
type: object
required: [sms_enabled, password_enabled, csrf_token]
properties:
sms_enabled: { type: boolean }
password_enabled: { type: boolean }
signup_enabled: { type: boolean, const: false }
csrf_token: { type: string }
default: { $ref: '#/components/responses/Failure' }
/api/v1/web/operator/login/sms/send:
post:
operationId: operatorSendLoginSMS
summary: 发送管理端登录验证码
description: 6 位随机验证码,5 分钟有效;每个手机号至少间隔 60 秒、每小时最多 5 次,家庭端和设备绑定入口共用此限额。同一请求号重试不重复发送。手机号加密、验证码仅存 keyed hash;不在响应中返回验证码。
security: [{ OperatorLoginCookie: [] }]
parameters:
- { $ref: '#/components/parameters/RequestID' }
- { $ref: '#/components/parameters/CSRF' }
requestBody:
required: true
content:
application/json:
schema: { $ref: './onboarding.yaml#/components/schemas/SMSSendInput' }
responses:
'200':
description: 网关已接受发送请求
content:
application/json:
schema: { $ref: './onboarding.yaml#/components/schemas/SMSResponse' }
default: { $ref: '#/components/responses/Failure' }
/api/v1/web/operator/login/sms/verify:
post:
operationId: operatorVerifyLoginSMS
summary: 验证验证码并创建管理端登录会话
description: 验证码只能在发起发送的浏览器会话使用,最多尝试 5 次,成功后一次性消费。已有短信账号复用原身份;管理端不开放自助注册,必须预先绑定已有有效管理身份。账号 Cookie 24 小时有效,调用家庭写接口还需 CSRF;保留原管理角色,写操作仍按现有角色权限校验。读取 /api/v1/me 或事件流需附带 X-Login-Portal=operator。
security: [{ OperatorLoginCookie: [] }]
parameters:
- { $ref: '#/components/parameters/RequestID' }
- { $ref: '#/components/parameters/CSRF' }
requestBody:
required: true
content:
application/json:
schema: { $ref: './onboarding.yaml#/components/schemas/SMSVerifyInput' }
responses:
'200':
description: 签发 HttpOnly 账号 Cookie,消费匿名登录会话;前端继续读取 /api/v1/me 校验业务账号
headers:
Set-Cookie:
schema: { type: string }
content:
application/json:
schema:
type: object
required: [ok, data]
properties:
ok: { type: boolean }
data:
type: object
required: [csrf_token, data]
properties:
csrf_token: { type: string }
data:
type: object
required: [authenticated]
properties:
authenticated: { type: boolean }
default: { $ref: '#/components/responses/Failure' }
/api/v1/web/operator/login/captcha:
post:
operationId: operatorLoginCaptcha
summary: 获取或更换密码登录、发送短信前的图片验证码
description: 返回 PNG 图片和随机 ID,不返回答案。绑定登录 Cookie,2 分钟有效;刷新使旧图失效;每次校验均消费验证码。校验状态保存在 Redis,依赖不可用时拒绝登录。
security: [{ OperatorLoginCookie: [] }]
parameters:
- { $ref: '#/components/parameters/RequestID' }
- { $ref: '#/components/parameters/CSRF' }
requestBody:
required: true
content:
application/json:
schema: { type: object, additionalProperties: false }
responses:
'200':
description: 图片验证码
content:
application/json:
schema:
type: object
required: [ok, data]
properties:
ok: { type: boolean }
data:
type: object
required: [captcha_id, mode, expires_at_ms]
properties:
captcha_id: { type: string, format: uuid }
mode: { type: string, enum: [image, tencent, slide] }
captcha_app_id: { type: string, description: 腾讯云模式对应客户端的公开 CaptchaAppId,不含密钥 }
image: { type: string, pattern: '^data:image/(png|jpeg);base64,' }
thumb_image: { type: string, pattern: '^data:image/png;base64,' }
image_width: { type: integer, minimum: 1 }
image_height: { type: integer, minimum: 1 }
thumb_width: { type: integer, minimum: 1 }
thumb_height: { type: integer, minimum: 1 }
thumb_x: { type: integer, minimum: 0, description: 拼图块的初始展示横坐标 }
thumb_y: { type: integer, minimum: 0, description: 拼图块所在水平轨道 }
expires_at_ms: { type: integer, format: int64 }
default: { $ref: '#/components/responses/Failure' }
/api/v1/web/operator/login/captcha/verify:
post:
operationId: operatorVerifyLocalSlideCaptcha
summary: 校验本地滑块位置并换取一次性票据
description: 同源、CSRF 和运营登录会话校验;挑战每次提交即消费。成功票据绑定原会话、客户端、策略版本和原到期时间,只能用于一次短信发送或密码登录。
security: [{ OperatorLoginCookie: [] }]
parameters:
- { $ref: '#/components/parameters/RequestID' }
- { $ref: '#/components/parameters/CSRF' }
requestBody:
required: true
content:
application/json:
schema: { $ref: './login-captcha.yaml#/components/schemas/SlideCaptchaVerifyInput' }
responses:
'200':
description: 位置正确,返回一次性校验票据
content:
application/json:
schema: { $ref: './login-captcha.yaml#/components/schemas/SlideCaptchaVerifyResponse' }
default: { $ref: '#/components/responses/Failure' }
/api/v1/web/operator/login/password:
post:
operationId: operatorLoginPassword
summary: 手机号、密码和图片验证码登录
description: 使用与短信登录一致的手机号身份,密码登录不自动注册。每手机号 10 分钟最多 10 次密码尝试;每登录会话最多 20 次。失败返回统一的手机号或密码错误,不暴露手机号是否注册。密码正确但没有该账号的有效设备验证 Cookie 时返回 403 NEW_DEVICE_SMS_REQUIRED,不消费登录会话、不发账号 Cookie;完成现有 LOGIN 短信验证后签发 30 天 HttpOnly 设备验证 Cookie。已验证设备成功消费登录会话,签发 24 小时账号 Cookie。
security: [{ OperatorLoginCookie: [] }]
parameters:
- { $ref: '#/components/parameters/RequestID' }
- { $ref: '#/components/parameters/CSRF' }
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [phone_e164, password, captcha_id]
anyOf:
- required: [captcha_code]
- required: [captcha_ticket]
properties:
phone_e164: { type: string, pattern: '^\+[1-9][0-9]{7,14}$' }
password: { type: string, minLength: 1, maxLength: 256, writeOnly: true }
captcha_id: { type: string, format: uuid }
captcha_code: { type: string, pattern: '^[0-9]{6}$', writeOnly: true }
captcha_ticket: { type: string, maxLength: 4096, writeOnly: true }
captcha_randstr: { type: string, maxLength: 256, writeOnly: true, description: 腾讯云 Web 模式必填,本地滑块模式无需提供 }
responses:
'200':
$ref: '#/paths/~1api~1v1~1web~1operator~1login~1sms~1verify/post/responses/200'
default: { $ref: '#/components/responses/Failure' }
/api/v1/web/operator/account/password:
get:
operationId: operatorPasswordState
summary: 查看当前手机号和密码设置状态
security: [{ OperatorAccountCookie: [] }]
responses:
'200':
description: 仅返回脱敏手机号、是否已设置密码、是否具有最近 10 分钟内且未消费的短信验证,不返回密码或摘要
content:
application/json:
schema:
type: object
properties:
ok: { type: boolean }
data:
type: object
required: [available]
properties:
available: { type: boolean }
phone_masked: { type: string }
password_configured: { type: boolean }
sms_verified_recently: { type: boolean }
default: { $ref: '#/components/responses/Failure' }
post:
operationId: operatorSetPassword
summary: 设置、修改或重置当前手机号的密码
description: 需要当前有效账号 Cookie、同源及 CSRF;同时需要最近 10 分钟内且未消费的短信验证,或正确的当前密码。新密码 6–64 个 Unicode 字符且不超过 256 字节。修改后清除短信证明并撤销该身份的其他管理登录会话,保留本次会话。密码使用随机盐 Argon2id 存储。
security: [{ OperatorAccountCookie: [] }]
parameters:
- { $ref: '#/components/parameters/RequestID' }
- { $ref: '#/components/parameters/CSRF' }
requestBody:
required: true
content:
application/json:
schema:
type: object
additionalProperties: false
required: [password]
properties:
password: { type: string, minLength: 6, maxLength: 64, writeOnly: true }
current_password: { type: string, maxLength: 256, writeOnly: true }
responses:
'200':
description: 密码已保存
content:
application/json:
schema:
type: object
properties:
ok: { type: boolean }
data:
type: object
properties:
password_configured: { type: boolean }
default: { $ref: '#/components/responses/Failure' }
/api/v1/web/operator/account/session:
get:
operationId: operatorAccountSession
summary: 恢复管理端登录会话并获取 CSRF
security: [{ OperatorAccountCookie: [] }]
responses:
'200':
description: 有效管理账号会话
content:
application/json:
schema:
type: object
properties:
ok: { type: boolean }
data:
type: object
required: [authenticated, csrf_token]
properties:
authenticated: { type: boolean }
csrf_token: { type: string }
default: { $ref: '#/components/responses/Failure' }
/api/v1/web/operator/auth/logout:
post:
operationId: operatorLogout
summary: 撤销当前管理端会话并清除其 Cookie
description: 同源与 CSRF 校验;家庭端会话不受影响。
security: [{ OperatorAccountCookie: [] }]
parameters:
- { $ref: '#/components/parameters/RequestID' }
- { $ref: '#/components/parameters/CSRF' }
requestBody:
required: true
content:
application/json:
schema: { type: object, additionalProperties: false }
responses:
'200':
description: 当前管理会话已退出
default: { $ref: '#/components/responses/Failure' }
components:
securitySchemes:
OperatorAccountCookie:
type: apiKey
in: cookie
name: __Host-platform-operator
description: 仅本地 HTTP 模式使用 platform-operator。与家庭端会话、密码独立;写操作需要同源及 CSRF。
OperatorLoginCookie:
type: apiKey
in: cookie
name: __Host-platform-operator-login
description: Secure、HttpOnly、SameSite=Lax;仅本地 HTTP 模式使用 platform-operator-login。
parameters:
RequestID:
in: header
name: X-Request-ID
required: true
schema: { type: string, format: uuid }
description: UUID v4,发送结果未知时用同一 ID 和正文重试。
CSRF:
in: header
name: X-CSRF-Token
required: true
schema: { type: string }
responses:
Failure:
description: 400/401/403/409/413/415/429/500/503;SMS_CODE_INVALID、LOGIN_SESSION_EXPIRED、SMS_RATE_LIMITED、SMS_SEND_UNCERTAIN、SMS_UNAVAILABLE、CAPTCHA_INVALID、CAPTCHA_UNAVAILABLE、PASSWORD_INVALID、PASSWORD_POLICY、CURRENT_PASSWORD_INVALID、SMS_REAUTH_REQUIRED、RATE_LIMITED 等,不返回验证码或密码。
content:
application/json:
schema: { $ref: './onboarding.yaml#/components/schemas/Failure' }