鉴权模型
API 使用 Bearer Token 鉴权,令牌与设备(客户端实例)一一对应:
Authorization: Bearer 3f8c2e...(64 位十六进制)
- 登录接口成功后由响应
data.user.token下发; - 服务端只存令牌的 sha256 摘要(不存明文),泄漏面小;
- 有效期 30 天,每次成功调用自动刷新最后活动时间续期(写库有 60 秒节流,无额外压力);
- 每个登录设备一个独立令牌,多端登录互不影响;退出登录只吊销当前令牌。
鉴权级别(三态):
| 级别 | 行为 |
|---|---|
| 公开(public) | 无须令牌,匿名可调 |
| 可选(optional) | 带令牌返回个性化数据(如"我是否已收藏"),不带也能调 |
| 必须(required) | 无有效令牌返回 401 UNAUTHORIZED |
另有「工作端」子策略:标记了 work_required 的接口除登录外还要求当前令牌绑定员工身份,否则返回 403 FORBIDDEN(详见《工作端接口》)。
未命中鉴权要求的响应示例:
{
"code": "UNAUTHORIZED",
"message": "登录已超时,请重新登录",
"data": {},
"errors": {},
"request_id": "9f2a5c8e1b3d7f40"
}
登录接口的公共结构
三种登录方式(账号密码、手机验证码、注册即登录)成功响应结构一致:
{
"code": "OK",
"message": "",
"data": {
"user": {
"user_id": 12,
"token": "3f8c2e...(64 位十六进制)",
"field": "email"
},
"dou": {
"auth": {
"is_work": false
}
}
},
"errors": {},
"request_id": "9f2a5c8e1b3d7f40"
}
| 字段 | 说明 |
|---|---|
data.user.user_id |
会员 ID |
data.user.token |
API 会话令牌,客户端持久化并在后续请求携带 |
data.user.field |
账号类型:email(邮箱)/ mobile(手机号) |
data.dou.auth.is_work |
是否绑定员工身份(决定工作端入口是否可用) |
验证码下发流程(注册 / 手机登录共用)
注册表单和手机验证码登录依赖「图形令牌 + 短信/邮件验证码」两步流程:
第 1 步:获取图形令牌对
GET /api/captcha/token
{
"code": "OK",
"message": "",
"data": {
"captcha_token": "...",
"storage_captcha_token": "..."
},
"errors": {},
"request_id": "9f2a5c8e1b3d7f40"
}
注册表单接口
user/register也会顺带下发这对令牌(连同promotion_user_sn、sns_token等注册上下文),客户端只需在表单初始化时调一次即可。
第 2 步:下发短信 / 邮件验证码
POST /api/captcha/verification
Content-Type: application/json
{
"type": "sms", // sms=短信 / email=邮件
"account": "13800000000", // 接收账号(手机号或邮箱)
"captcha_token": "...", // 第 1 步返回
"storage_captcha_token": "...",// 第 1 步返回
"check": "no_allow_phone_exist" // 业务策略:注册场景用默认值(拦截已注册账号);登录场景传空串
}
成功响应 data 即「验证数据」(verification_data):
{
"code": "OK",
"message": "",
"data": {
"account": "13800000000",
"ontime": 1760000000,
"code": "服务端生成的验证码校验摘要"
},
"errors": {},
"request_id": "9f2a5c8e1b3d7f40"
}
重要约定:data 的内容由服务端签发(内含验证码校验摘要与发送时间 ontime),客户端原样保存、原样透传给注册 / 登录提交接口(作为 verification_data,JSON 字符串或对象均可,服务端会自动解析),不要修改或解析。验证码有效期 5 分钟;过期或与账号不匹配会返回 422,errors.verification 给出具体原因。
接口清单
| 方法 | 路径 | 鉴权 | 说明 |
|---|---|---|---|
| GET | /api/user/register |
公开 | 注册表单上下文(下发令牌对与注册配置) |
| POST | /api/user/register_post |
公开 | 注册提交(成功后直接登录,返回令牌) |
| POST | /api/user/login_post |
公开 | 账号密码登录 |
| POST | /api/user/login_phone_post |
公开 | 手机验证码登录 |
| GET | /api/user/password_reset |
公开 | 忘记密码表单(返回页面标题) |
| POST | /api/user/password_reset_post |
公开 | 忘记密码提交(向邮箱发送重置链接邮件) |
| POST | /api/user/logout |
必须 | 退出登录(吊销当前令牌) |
| POST | /api/user/check_login_state |
公开 | 检查登录态(未登录不报 401) |
注册
表单上下文 GET /api/user/register?user_sn=xxx&sns_token=yyy(参数均可选):
{
"code": "OK",
"message": "",
"data": {
"captcha_token": "...",
"storage_captcha_token": "...",
"promotion_user_sn": "xxx",
"sns_token": "yyy",
"login_mode": "email",
"mail_username": 1,
"sms_accessKeyId": 0
},
"errors": {},
"request_id": "9f2a5c8e1b3d7f40"
}
| 字段 | 说明 |
|---|---|
login_mode |
站点注册方式:email / (短信) |
mail_username |
1=已配置邮件发信,邮箱验证码区可展示 |
sms_accessKeyId |
1=已配置短信通道,短信验证码区可展示 |
注册提交 POST /api/user/register_post:
| 参数 | 必填 | 说明 |
|---|---|---|
email 或 mobile |
二选一 | 提供哪个走哪种注册方式;邮箱走 email,手机走 mobile |
password |
是 | 密码 |
password_confirmation |
是 | 确认密码(须一致) |
verification |
条件 | 当站点开启了邮箱/短信验证时必须提供(第 2 步发的验证码) |
verification_data |
条件 | 第 2 步返回的验证数据(JSON 字符串,原样透传) |
promotion_user_sn |
否 | 推广人编号(分销场景透传) |
sns |
否 | 第三方绑定数据(JSON 字符串,登录后自动关联) |
成功响应同「登录接口的公共结构」,客户端拿 data.user.token 即可开始调用其它接口。
账号密码登录
POST /api/user/login_post
Content-Type: application/json
{ "username": "user@example.com", "password": "******" }
username可填邮箱或手机号(field自动识别);- 失败返回
422,errors中给出账号或密码错误原因(出于安全,不区分"账号不存在"与"密码错误"); - 该接口限流 5 次/60 秒。
手机验证码登录
POST /api/user/login_phone_post
Content-Type: application/json
{
"mobile": "13800000000",
"verification": "123456",
"verification_data": { "...": "第 2 步返回,原样透传" },
"promotion_user_sn": ""
}
- 第 2 步下发验证码时
check传空串(登录场景不拦截已存在账号,反而要求账号存在); - 登录成功若账号尚未注册会按站点策略自动处理(以实际返回为准);
- 该接口限流 5 次/60 秒。
忘记密码
POST /api/user/password_reset_post,参数email(必须为已注册邮箱):- 邮箱不存在 →
404 NOT_FOUND,errors.email提示; - 发送失败 →
500 SERVER_ERROR; - 成功 →
200 OK,message提示已发送(邮件内含带uid与code的重置链接,点开在网页端继续重置)。
- 邮箱不存在 →
GET /api/user/password_reset仅返回表单标题,供客户端渲染页面头部。
该接口限流 5 次/300 秒。
登录态检查与退出
检查登录态 POST /api/user/check_login_state:
// 已登录
{ "code": "OK", "message": "", "data": { "login_state": true }, "errors": {}, "request_id": "..." }
// 未登录(注意:HTTP 仍是 200,不报 401)
{ "code": "OK", "message": "", "data": { "login_state": false }, "errors": {}, "request_id": "..." }
适合应用启动时静默探测本地令牌是否仍有效,不触发 401 错误流。
退出登录 POST /api/user/logout(须带令牌):
{ "code": "OK", "message": "", "data": {}, "errors": {}, "request_id": "..." }
吊销当前设备令牌;其它设备已下发的令牌不受影响。客户端应同时清空本地令牌。
令牌失效排查
收到 401 UNAUTHORIZED 时按客户端的标准动作处理:清除本地令牌 → 跳登录页。常见原因:
| 现象 | 原因 |
|---|---|
| 所有必须鉴权接口都 401 | 未带回 Authorization 头,或头格式缺 Bearer 前缀 |
| 单次偶发 401 | 令牌被其它设备退出、或后台吊销 |
| 登录后过一段时间开始 401 | 令牌超过 30 天未活动过期 |
修改密码与资料
均要求登录,详见《会员接口》:
| 接口 | 说明 |
|---|---|
POST /api/user/password_post |
修改密码(old_password + password + password_confirmation);成功返回 data.relogin=true,建议客户端引导重新登录 |
GET /api/user/edit / POST /api/user/edit_post |
资料编辑表单与保存 |
POST /api/user/upload_avatar |
头像上传(multipart) |