373 lines
10 KiB
Markdown
373 lines
10 KiB
Markdown
# Heicode 客户端 — 登录接口对接文档
|
||
|
||
**版本**: v1.0
|
||
**生效日期**: 2026-04-30
|
||
**状态**: 已上线生产,已通过端到端测试
|
||
|
||
---
|
||
|
||
## 1. 概述
|
||
|
||
本文档描述 Heicode 客户端(桌面/CLI)与 Heicode Manager(即 mcp-server)之间的**登录认证接口**。共 4 个接口,覆盖完整登录生命周期:
|
||
|
||
|
||
| 接口 | 用途 |
|
||
| ------------------------ | ----------------------- |
|
||
| `POST /api/auth/login` | 账号密码登录,换取 token |
|
||
| `GET /api/auth/me` | 校验 token 有效性 + 获取当前用户资料 |
|
||
| `POST /api/auth/refresh` | access token 过期时换新的 |
|
||
| `POST /api/auth/logout` | 登出(token 加入黑名单) |
|
||
|
||
|
||
> 不在本期范围:注册、找回密码、改密码 — 这些走官网 web 端完成。
|
||
|
||
---
|
||
|
||
## 2. 接入信息
|
||
|
||
### 2.1 Base URL
|
||
|
||
生产环境通过 Azure APIM 网关接入:
|
||
|
||
```
|
||
https://apimtaiji.azure-api.net/api/mcp
|
||
```
|
||
|
||
完整路径示例:
|
||
|
||
```
|
||
POST https://apimtaiji.azure-api.net/api/mcp/api/auth/login
|
||
```
|
||
|
||
### 2.2 通用请求头
|
||
|
||
|
||
| Header | 必填 | 说明 |
|
||
| -------------------------------- | ----------- | -------------- |
|
||
| `Content-Type: application/json` | 是(POST/PUT) | 请求体 JSON |
|
||
| `Authorization: Bearer <token>` | 受保护接口必填 | 见 §3 |
|
||
| `X-Request-Id: <uuid>` | 建议 | 全链路追踪 ID,客户端生成 |
|
||
|
||
|
||
### 2.3 Token 模型
|
||
|
||
登录成功返回两个 token:
|
||
|
||
|
||
| Token | 用途 | 有效期 |
|
||
| ----------------- | ------------------------ | ----- |
|
||
| **Access Token** | 调业务接口(含 `/me`、`/logout`) | 24 小时 |
|
||
| **Refresh Token** | 仅用于 `/refresh` 换新 access | 7 天 |
|
||
|
||
|
||
JWT claims 包含:`sub`(user_id)、`email`、`role`、`channelId`、`type`(access/refresh)、`iat`、`exp`。
|
||
|
||
---
|
||
|
||
## 3. 接口详情
|
||
|
||
### 3.1 POST /api/auth/login — 登录
|
||
|
||
**请求**
|
||
|
||
```http
|
||
POST /api/auth/login HTTP/1.1
|
||
Content-Type: application/json
|
||
|
||
{
|
||
"email": "user@example.com",
|
||
"password": "YourPassword123",
|
||
"role": "user"
|
||
}
|
||
```
|
||
|
||
字段:
|
||
|
||
- `email` (string, 必填)
|
||
- `password` (string, 必填)
|
||
- `role` (string, 必填):Heicode 客户端**固定传 `"user"`**
|
||
|
||
**成功响应 200**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"token": "eyJhbGciOiJIUzI1NiIs...",
|
||
"refreshToken": "eyJhbGciOiJIUzI1NiIs...",
|
||
"user": {
|
||
"id": "b00a7b8e-9e8b-463d-9593-a3b4d0006778",
|
||
"name": "张三",
|
||
"email": "user@example.com",
|
||
"role": "user",
|
||
"channelId": "6e6fc470-76f8-4bb1-8ea4-625dc5b12bc6"
|
||
}
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误响应**
|
||
|
||
|
||
| HTTP | 含义 | 客户端处理建议 |
|
||
| ---- | ------------------------- | -------------------------------- |
|
||
| 401 | 邮箱或密码错误 | 显示"账号或密码错误",让用户重新输入 |
|
||
| 403 | 账户已被禁用 | 提示用户联系管理员 |
|
||
| 429 | 登录尝试过于频繁(**每 IP 5 次/分钟**) | 显示倒计时;响应头 `Retry-After: 60` 表示秒数 |
|
||
| 422 | 请求体校验失败(邮箱格式不合法等) | 检查 `detail` 字段 |
|
||
| 500 | 服务异常 | 重试或提示稍后再试 |
|
||
|
||
|
||
**重要:限流规则**
|
||
|
||
- **每 IP 每分钟最多 5 次**登录尝试(不区分成功失败)
|
||
- 超出返回 **429 Too Many Requests**,含 `Retry-After` 头(秒)
|
||
- 计数滑动窗口,60 秒后自动恢复
|
||
|
||
---
|
||
|
||
### 3.2 GET /api/auth/me — 获取当前用户
|
||
|
||
客户端**启动时**应调用此接口校验本地缓存的 access token 是否仍有效,并刷新用户信息。
|
||
|
||
**请求**
|
||
|
||
```http
|
||
GET /api/auth/me HTTP/1.1
|
||
Authorization: Bearer <accessToken>
|
||
```
|
||
|
||
**成功响应 200**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"id": "b00a7b8e-9e8b-463d-9593-a3b4d0006778",
|
||
"email": "user@example.com",
|
||
"name": "张三",
|
||
"role": "user",
|
||
"channelId": "6e6fc470-76f8-4bb1-8ea4-625dc5b12bc6",
|
||
"status": "active",
|
||
"subscriptionTier": "free",
|
||
"lastLoginAt": "2026-04-30T06:38:14.765457"
|
||
}
|
||
}
|
||
```
|
||
|
||
**错误响应**
|
||
|
||
|
||
| HTTP | 含义 | 客户端处理建议 |
|
||
| ---- | --------------------- | ------------------------------------------ |
|
||
| 401 | Token 无效/过期/已登出/用户不存在 | 调 `/refresh` 换新 token;若 refresh 也 401,跳登录页 |
|
||
| 403 | 账户已被禁用 | 强制登出,提示联系管理员 |
|
||
|
||
|
||
---
|
||
|
||
### 3.3 POST /api/auth/refresh — 刷新 token
|
||
|
||
access token 接近或已过期时调用,使用 **refresh token** 换取新的 access + refresh token 对。
|
||
|
||
**请求**
|
||
|
||
```http
|
||
POST /api/auth/refresh HTTP/1.1
|
||
Authorization: Bearer <refreshToken>
|
||
```
|
||
|
||
> ⚠️ **必须传 refresh token**,传 access token 会被拒绝。
|
||
|
||
**成功响应 200**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": {
|
||
"token": "eyJhbGciOiJIUzI1NiIs...",
|
||
"refreshToken": "eyJhbGciOiJIUzI1NiIs..."
|
||
}
|
||
}
|
||
```
|
||
|
||
客户端收到新的 token 对后**应替换本地缓存**(包括 refresh token,旧的也作废)。
|
||
|
||
**错误响应**
|
||
|
||
|
||
| HTTP | 含义 | 客户端处理建议 |
|
||
| ---- | ---------------------------------------- | ------- |
|
||
| 401 | refresh token 无效 / 过期 / 错传了 access token | 跳登录页 |
|
||
|
||
|
||
实施细节:
|
||
|
||
- 服务端会校验 token claims `type == "refresh"`,否则拒绝
|
||
- 旧 refresh token 不会被立即吊销(容许并发换发期),但客户端应丢弃旧的
|
||
|
||
---
|
||
|
||
### 3.4 POST /api/auth/logout — 登出
|
||
|
||
将当前 access token 加入黑名单,使其立即失效。
|
||
|
||
**请求**
|
||
|
||
```http
|
||
POST /api/auth/logout HTTP/1.1
|
||
Authorization: Bearer <accessToken>
|
||
```
|
||
|
||
**成功响应 200**
|
||
|
||
```json
|
||
{
|
||
"success": true,
|
||
"data": null,
|
||
"message": "登出成功"
|
||
}
|
||
```
|
||
|
||
**错误响应**
|
||
|
||
logout 容错性较强,token 黑名单写入失败也会返回 200(前端清理本地 token 即可)。
|
||
|
||
**客户端登出流程**:
|
||
|
||
1. 调 `/api/auth/logout`
|
||
2. 清除本地存储的 access + refresh token
|
||
3. 清除当前用户资料缓存
|
||
4. 跳转到登录页
|
||
|
||
---
|
||
|
||
## 4. 完整登录流程(示例)
|
||
|
||
### 启动时
|
||
|
||
```
|
||
┌─ 本地有 access token ?
|
||
│
|
||
├─ 是 ─→ GET /me
|
||
│ ├─ 200 ─→ 进入主界面
|
||
│ └─ 401 ─→ 本地有 refresh token ?
|
||
│ ├─ 是 ─→ POST /refresh
|
||
│ │ ├─ 200 ─→ 替换 token,进入主界面
|
||
│ │ └─ 401 ─→ 跳登录页
|
||
│ └─ 否 ─→ 跳登录页
|
||
│
|
||
└─ 否 ─→ 跳登录页
|
||
```
|
||
|
||
### 登录页提交
|
||
|
||
```
|
||
POST /login
|
||
├─ 200 ─→ 存 token 对,进主界面
|
||
├─ 401 ─→ 显示"账号或密码错误"
|
||
├─ 429 ─→ 显示"尝试过于频繁,请 N 秒后重试"(N 取响应头 Retry-After)
|
||
└─ 其他 ─→ 显示通用错误
|
||
```
|
||
|
||
### 业务请求过程中 access token 过期
|
||
|
||
```
|
||
任意业务接口返回 401
|
||
└─→ POST /refresh (用 refresh token)
|
||
├─ 200 ─→ 替换 token,重试原请求
|
||
└─ 401 ─→ 清理 token,跳登录页
|
||
```
|
||
|
||
### 登出按钮
|
||
|
||
```
|
||
POST /logout
|
||
└─→ 不论结果都清理本地 token,跳登录页
|
||
```
|
||
|
||
---
|
||
|
||
## 5. 错误响应格式
|
||
|
||
当前为 FastAPI 默认格式(下个版本 `/api/v1/*` 路径会改为标准 envelope,本期保留兼容):
|
||
|
||
```json
|
||
{
|
||
"detail": "邮箱或密码错误"
|
||
}
|
||
```
|
||
|
||
422 校验错误格式(Pydantic):
|
||
|
||
```json
|
||
{
|
||
"detail": [
|
||
{
|
||
"type": "value_error",
|
||
"loc": ["body", "email"],
|
||
"msg": "value is not a valid email address: ...",
|
||
"input": "abc"
|
||
}
|
||
]
|
||
}
|
||
```
|
||
|
||
---
|
||
|
||
## 6. 安全注意事项
|
||
|
||
|
||
| 项 | 说明 |
|
||
| -------------- | -------------------------------------------------------------------------------------- |
|
||
| **token 存储** | 桌面应用建议存到 OS 安全凭据存储(Windows Credential Manager / macOS Keychain / Linux Secret Service) |
|
||
| **HTTPS 强制** | 生产 base URL 已是 HTTPS;客户端**禁止**回退 HTTP |
|
||
| **token 泄露应对** | 用户怀疑泄露时提示去官网 web 端改密码(改密会导致所有 session 黑名单) |
|
||
| **审计日志** | 所有 login 尝试(成功/失败)服务端均写审计 |
|
||
| **状态码不泄漏** | 错误信息已统一用"邮箱或密码错误",不区分账号是否存在,防爆破 |
|
||
|
||
|
||
---
|
||
|
||
## 7. 测试账号(仅供联调)
|
||
|
||
|
||
| 角色 | 邮箱 | 密码 |
|
||
| ---- | ----------- | ------------ |
|
||
| 普通用户 | `55@55.com` | `By@123456.` |
|
||
|
||
|
||
> ⚠️ 测试账号仅用于联调阶段,正式上线前请务必关闭。
|
||
|
||
---
|
||
|
||
## 8. 已上线生产验证清单
|
||
|
||
|
||
| 测试项 | 结果 |
|
||
| ------------------------------------------ | --- |
|
||
| login 200 + 返回 access/refresh token | ✅ |
|
||
| /me 用 access token → 200 + 完整 profile | ✅ |
|
||
| /refresh 用 refresh token → 200 + 新 token 对 | ✅ |
|
||
| /refresh 用 access token → 401 拒绝 | ✅ |
|
||
| logout → 200 | ✅ |
|
||
| logout 后旧 token 调 /me → 401(黑名单生效) | ✅ |
|
||
| 连续 7 次错密 → 第 6 次起 429(每 IP 5/min 限流) | ✅ |
|
||
| 服务器审计日志记录所有 login(含成功/失败) | ✅ |
|
||
|
||
|
||
镜像 digest: `sha256:339b64ae090dc81fa13cb29705958167e77fe0698e27ac227c05054ed5c42309`
|
||
镜像 tag: `taiji.azurecr.io/mcp-server:heicode-auth-fix2-20260430`
|
||
部署日期: 2026-04-30
|
||
|
||
---
|
||
|
||
## 9. 联系
|
||
|
||
如对接过程发现接口行为与本文档不一致,请联系 Heicode Manager 后端团队,附上:
|
||
|
||
- 请求完整 URL / Headers / Body
|
||
- 响应 HTTP 状态 + Body
|
||
- `X-Request-Id` 头值(便于服务端按 ID 反查日志)
|
||
|