跳转到正文
图奕科技 开发文档 平台登录
接入指南 / 找回与设置密码下载本章 Markdown ↓

本实例 Issuer https://platform.too1.net

找回与设置密码

短信发送须先完成滑块验证,并在原发送请求中携带一次性 captcha_token;发布前同步升级相关客户端。

官网和原生桌面都可以不跳页完成密码管理。此权限默认关闭;管理员在 OIDC 客户端编辑页开启“直接找回 / 设置密码”。Web 同时要求自定义网页登录开关和 Origin;Native 同时要求原生登录开关。密码事务与登录事务不能混用,不能用短信改密证明领取登录授权码。

选择操作

operation 身份条件 手机号 成功结果
reset 无需已有用户登录;Web 后端仍 Basic 用户输入 +86 E.164 不注册、不激活 pending_activation;仅更改 active 账号密码
set 有效的该 Client 用户 Access Token 从 Token 对应账号确定;不能换成其他手机号 设置/更改该账号密码

两者都须本事务重新验证短信。验证前不根据账号存在与否改变发送结果;未注册手机号也走同一渠道和限流。短信验证后账号不可用返回统一失败。接口不能用于枚举完整手机号。

创建

Web:POST /api/v1/web-auth/password-transactions,后端 Web Basic,无 Origin、Cookie 或查询参数。

{"client_id":"wyc-web","operation":"reset","browser_origin":"https://www.example.com"}

设置密码在请求体额外加入 user_access_token,由产品后端从当前业务会话读取。浏览器不能提交任意用户 Token 让后端代用。

Native:POST /api/v1/native-auth/password-transactions,JSON {"client_id":"wyc-desktop","operation":"reset"}。设置时 operation 为 set,头为 Authorization: Bearer <该Client有效用户AccessToken>,不在 JSON 传 Token。不接受浏览器头或 Cookie。

响应 HTTP 201:

{"data":{"transaction_id":"ef1ff5ec-ecc3-449b-bd5c-951d0c349d67","transaction_token":"oVFXTKbI1uygV9ytwf3vUFt9iEEWFtebUUvmcmTXXDk","status":"waiting","expires_in":300,"expires_at":"2026-09-03T09:05:00Z","phone_masked":"+86****8000","operation":"set"}}

字段 client_id 最长 128;operation 只能 set/reset;browser_origin 是 Web 必填的登记来源;user_access_token 仅 Web set,最长 8192。后续请求只带事务凭据,不再发送用户 Access Token。reset 返回的 phone_masked 不包含用户信息。

发送、验证、完成、取消

下文 base 为创建 URL 加 /{transaction_id}。Web 浏览器使用 Authorization: WebAuth <transaction_token>、Origin 和 credentials:omit;Native 使用 Authorization: Native <transaction_token>。POST 一律 JSON;不接受未知字段、查询参数、Cookie。

方法 / URL reset 请求体 set 请求体 成功
GET base 无 无 200 data.status / expires_at / phone_masked;两秒串行轮询
POST base/sms/send {"phone_e164":"+8613800138000"} {} 201 accepted 或 202 unknown,retry_after=60
POST base/sms/verify {"phone_e164":"+8613800138000","code":"123456"} {"code":"123456"} 200 {"data":{"status":"ready"}}
POST base/complete {"new_password":"NewStrongPassword123"} 同左 200 {"data":{"status":"completed","relogin_required":true}}
POST base/cancel {} {} 200 {"data":{"status":"cancelled"}}

set 可省略手机号;如提交必须等于账号当前手机号。短信挑战绑定事务 UUID,不能用于另一事务、登录或其他用途。new_password 使用统一密码策略:10–128 字节,含英文字母与数字;Argon2id 存储,不记录原文。示例密码只是格式示例,真实用户须自行设置。

密码提交必须 ready。密码更新、中央会话撤销、Access/Refresh Token 撤销、未完成认证事务取消及 user.sessions_revoked Outbox 在同一数据库事务提交。回滚则都不生效。完成前再次验证账号状态、手机号、认证版本;set 再次验证源 Access Token 未过期或撤销。

成功后不自动登录,不返回授权码或新 Token。产品后端处理签名事件撤销自己的业务会话;官网示例也退出当前产品会话。只撤销中央状态不能保证尚未消费事件的产品业务会话立即退出。

错误与恢复

外层错误统一为 {"error":{"code":"invalid_user_token","message":"用户 Token 无效、已过期或已撤销","request_id":"诊断编号"}}。

除 自定义 Web 错误表 外:401 invalid_user_token 表示需重新登录;422 password_policy 表示新密码不合策略;422 invalid_phone 表示 set 试图验证其他手机号;422 invalid_code 为验证码/账号不可用;409 transaction_unavailable 表示事务结束、过期、撤销或并发修改。Redis/数据库错误返回 503 storage_unavailable,不当作验证码错误。

Native 创建每 IP 30 次/5 分钟;Web 创建使用每 Client 600 次/分钟及后端 IP 1,200 次/分钟,与登录事务共用。完成每事务最多 5 次/5 分钟;短信共享全局限流。POST 没有自动重试。密码提交网络超时后结果未知:重新登录验证新密码,必要时重新发起找回;不得复用旧证明自动改第二次。忘记密码不会让账号解除管理员禁用。

Go / Rust / Tauri

使用标准 HTTPS 客户端;事务 Token 放请求头,禁止 JS WebView 调 Native API。Tauri 前端调用 Rust command,由 Rust reqwest 直接请求平台;对 command 做窗口/能力白名单,不开放任意 URL 代理。新密码只在调用内存中存在;返回前清空 UI 输入。不要把业务 Service Secret 打进安装包。

Go 可使用 http.NewRequestWithContext,POST 内容 json.Marshal,超时 12 秒。Rust:

// HTTP 在 Rust 层,不是 WebView fetch;client 禁止自动重定向。
let client = reqwest::Client::builder()
    .timeout(std::time::Duration::from_secs(12))
    .redirect(reqwest::redirect::Policy::none()).build()?;
let response = client.post(format!("{issuer}/api/v1/native-auth/password-transactions/{id}/complete"))
    .header("Authorization", format!("Native {transaction_token}"))
    .json(&serde_json::json!({"new_password": new_password}))
    .send().await?;
// 检查 HTTP 状态及 error.code;不使用 unwrap,不把 body/Token 写日志。

仓库及发布包的 examples/native-password/client.go 提供完整 Go 适配器,包含创建、发送、验证、完成、取消、超时和安全错误;password.rs 提供 Rust/Tauri 适配示例(需在产品 Cargo 工程集成验证)。官网可运行样例位于 examples/custom-web,包括同样的密码流程。原生登录的验签、刷新和系统凭据保存见 Native。设计参考 OWASP Forgot Password。