返回博客

调接口老返回未登录?怡途Claw 登录注册与 Token 鉴权 API 全流程实战

2026年7月31日阅读约 19 分钟
怡途Claw 登录鉴权 API 实战

怡途Claw 所有 /api/app/* 接口都要带 JWT token。本文从后端代码拆解 send-verify-code、register、login 三个鉴权接口的请求响应,token 的 24 小时过期与 Bearer 头用法,以及注销即失效的校验细节。

前面几篇讲了怎么部署实例、对话、传文件、管会话。但所有 /api/app/* 接口都有一个前提:你得先拿到一个登录 token,放在请求头里,不然直接返回 401。

实际接进来会碰到几个问题:

  • 调接口老返回 未登录,到底要带什么头?
  • token 是怎么来的,注册和登录返回的 token 有区别吗?
  • token 能用多久,过期了怎么办?
  • 用户注销了账号,他手上那个老 token 还能不能继续调接口?

怡途Claw 的鉴权用 JWT。本文直接从 /api/app/auth 这组接口和后端代码来看 token 是怎么签发、怎么校验的。

整体流程

三步:

  1. 没账号就先注册:发验证码 -> 注册(拿到 token)
  2. 有账号就登录:手机号或邮箱 + 密码 -> 登录(拿到 token)
  3. 之后所有 /api/app/* 接口,请求头带 Authorization: Bearer <token>

token 本身是一串 JWT,后端校验签名和过期时间就能知道是谁。但每次请求还会额外查一次库确认账号还在不在,原因后面讲。

第一步:发验证码 POST /api/app/auth/send-verify-code

注册前要先拿验证码。请求体只有一个字段:

{ "phone": "13800138000" }

手机号必须符合 1[3-9] 开头的 11 位格式,不然后端 DTO 直接挡掉,返回 手机号格式不正确

接口有两个路径别名,/api/app/auth/send-verify-code/api/app/auth/sms/send 指向同一个处理函数,都能用。

返回:

{ "success": true, "message": "验证码已发送", "phone": "13800138000" }

一个细节:在 development 或 test 环境下,返回里会多一个 devCode 字段,直接把 6 位验证码明文带回来,方便联调。生产环境没有这个字段,验证码只走短信。

第二步:注册 POST /api/app/auth/register

请求体:

{
  "phone": "13800138000",
  "verifyCode": "123456",
  "password": "yourpass",
  "confirmPassword": "yourpass",
  "name": "可选昵称",
  "inviteCode": "1234"
}

字段约束(DTO 层强制的):

  • verifyCode 必须正好 6 位
  • passwordconfirmPassword 都至少 6 位,两次要一致
  • name 可选
  • inviteCode 可选,填的话必须是 4 位数字

注册成功直接返回 token,不用再调一次登录:

{
  "success": true,
  "data": {
    "user": {
      "id": 101,
      "phone": "13800138000",
      "name": "可选昵称",
      "role": "user",
      "agent": { "...": "该用户的 agent 概要" }
    },
    "token": "eyJhbGciOiJIUzI1NiIs..."
  }
}

返回里的 agent 是该用户的 agent 概要信息,注册时一并带回来,前端可以直接拿去渲染。

第三步:登录 POST /api/app/auth/login

已经注册过的账号,直接登录拿 token。请求体:

{ "phone": "13800138000", "password": "yourpass" }

或者用邮箱:

{ "email": "you@example.com", "password": "yourpass" }

phoneemail 都是可选的,二选一,password 必填。返回结构和注册一模一样:{ user, token }

代码里登录会比注册多做一件事:更新 lastLoginAt。所以登录接口除了签发 token,还会顺手记一下本次登录时间。

token 里装了什么

后端签 token 时塞进去的 payload 是这三个字段:

{ "phone": "...", "sub": userId, "role": "user" }

sub 就是用户 id,后端校验 token 后从 sub 拿到当前用户。也就是说你在文件上传那篇里传文件、会话管理那篇里建会话,后端都是靠这个 sub 知道"这是谁家的实例"。

两个关键配置:

  • 过期时间 1d,token 签发后 24 小时失效。过了这个时间再带上去调接口,后端 ignoreExpiration 设为 false,直接判过期拒绝。
  • 签名密钥是服务端的 JWT_SECRET,token 是后端签的也是后端验的,客户端没法伪造 sub 去冒充别人。

怎么带 token 调接口

拿到 token 之后,所有挂在 JwtAuthGuard 下的 /api/app/* 接口都要在请求头加:

Authorization: Bearer eyJhbGciOiJIUzI1NiIs...

后端用 ExtractJwt.fromAuthHeaderAsBearerToken() 从这个头里把 token 抠出来。忘了带、带错格式,都是 401 未登录

验证一下自己是谁,调 GET /api/app/auth/me

curl https://www.yitukeji.cn/api/app/auth/me \
  -H "Authorization: Bearer <你的token>"

返回当前用户资料,带 subscriptionpackageagent 三个聚合字段。能调通说明 token 有效。这个接口和 GET /api/app/users/profile 返回的内容基本一致,区别是 auth/me 语义上偏"我是谁",users/profile 偏"我的资料",按需选一个。

一个容易被忽略的细节:注销即失效

JWT 本身是无状态的,理论上 token 签发后在过期前一直有效,服务端不存它。但怡途Claw 的校验逻辑里多了一步:每次请求都会拿 sub 去数据库查一次用户,看 isActive 字段。

这意味着:

  • 用户注销账号后(isActive 置为 false),他手上那个还没过期的老 token 立刻就废了,下一次请求直接返回 账户已注销
  • 不用等 24 小时自然过期。

代价是每个鉴权请求多一次 DB 查询。代码注释里写得很直白:注销后能立即生效比性能重要。对一个按 token 计费、可能涉及客户数据的平台来说,这个取舍是合理的。

这也引出一个实操建议:客户端不要只把 token 存下来就完事,最好在收到 账户已注销 这类 401 时清掉本地 token 并跳回登录页,别拿着废 token 一直重试。

邀请码校验 GET /api/app/auth/invite-code/:inviteCode

注册时如果填了邀请码,可以先调这个接口校验合不合法:

curl https://www.yitukeji.cn/api/app/auth/invite-code/1234

合法返回邀请码对应的信息,不合法返回对应错误。这个接口不需要登录,可以放在注册表单填完邀请码、输入框失焦时做即时校验,避免提交到 register 才发现邀请码不对。

小结

接怡途Claw 的 API,鉴权这条线就三件事:

  1. 没账号走 send-verify-code -> register,有账号走 login,都能拿到 token。
  2. token 是 24 小时有效的 JWT,每次请求带 Authorization: Bearer <token>
  3. 账号注销后老 token 立即失效,不用等过期。

token 拿到之后,前面几篇讲的部署、对话、文件、会话、实例生命周期那些接口就都能调了。这串 token 就是进入整套 /api/app/* 的门票。