85 lines
2.2 KiB
Markdown
85 lines
2.2 KiB
Markdown
# 8.7 Token 使用说明
|
||
|
||
:::tip 概述
|
||
客户端持有 access_token + refresh_token 双令牌:请求携带 access,过期后用 refresh 兑换新令牌。401 是唯一的"令牌失效"信号。本页字段以 `internal/model/dto/auth.go` 为准。
|
||
:::
|
||
|
||
## 获取
|
||
|
||
```text
|
||
POST /api/login(公开,参数支持 query/body 混合提交)
|
||
{
|
||
"username": "...",
|
||
"password": "...",
|
||
"key": "<captcha 接口返回的 key>",
|
||
"code": "<验证码>",
|
||
"tenantCode": "" // 留空按用户名全局定位
|
||
}
|
||
|
||
响应 data(LoginRes):
|
||
{
|
||
"access_token": "eyJ...",
|
||
"refresh_token": "eyJ...",
|
||
"expires_in": 7200,
|
||
"token_type": "Bearer"
|
||
}
|
||
```
|
||
|
||
## 携带
|
||
|
||
```http
|
||
Authorization: Bearer eyJ...
|
||
```
|
||
|
||
前端请求拦截器自动附加;业务代码不手工处理。
|
||
|
||
## 刷新
|
||
|
||
```text
|
||
POST /api/oauth2/token(公开)
|
||
grant_type=refresh_token 模式:
|
||
{ "grant_type": "refresh_token", "refresh_token": "<refresh_token>" }
|
||
|
||
grant_type=password 模式(兑换):
|
||
{ "grant_type": "password", "username": "...", "password": "...", "code": "...", "key": "..." }
|
||
```
|
||
|
||
响应 RefreshRes 结构与登录一致(access_token / refresh_token / expires_in / token_type)。旧 refresh 拉黑(防重放)。
|
||
|
||
## 校验
|
||
|
||
```text
|
||
GET /api/oauth2/check/token(携带 Authorization)
|
||
响应(CheckTokenRes):{ "valid": true, "userId": 1 }
|
||
```
|
||
|
||
valid=false 时 userId 按 0 返回。
|
||
|
||
## 失效场景
|
||
|
||
| 场景 | 表现 |
|
||
|---|---|
|
||
| access 过期 | 401 → 前端刷新或跳登录 |
|
||
| 登出 | 双令牌入黑名单,立即失效 |
|
||
| 强制下线 | 指定会话双令牌拉黑 |
|
||
| 撤销 | DELETE /api/oauth2/remove/:token(管理员) |
|
||
|
||
黑名单 TTL = 令牌剩余有效期,到期自然失效,无需清理。
|
||
|
||
## 客户端处理建议
|
||
|
||
```text
|
||
收到 401 →
|
||
有 refresh_token 且未尝试过 → 调 /api/oauth2/token 刷新 → 重放原请求(刷新只尝试一次,防死循环)
|
||
否则 → 清本地令牌 → 跳登录页
|
||
```
|
||
|
||
## 调试
|
||
|
||
Swagger 调试:先登录拿 access_token,在文档页填入 Authorization 后调用受保护接口。
|
||
|
||
## 相关
|
||
|
||
- [5.1 用户认证(JWT)](/zh/core/jwt.html)
|
||
- [5.2 认证与授权流程](/zh/core/auth-flow.html)
|