Blog posts and course content are currently in Chinese. Translation is in progress.
Back to Blog

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

2026年7月31日19 min read
怡途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/* 的门票。