用户管理服务接入方案
本文只描述方案,不展开代码实现。推荐采用“接口接入”的方式:用户管理服务继续作为用户主数据来源,flow-talk-server 只通过 HTTP 接口校验登录态、读取用户资料,并签发 IM 自己的 token。
目标
- 用户账号、密码、组织、禁用状态由用户管理服务维护。
- IM 服务不保存外部 access token,不直接管理外部账号密码。
- IM 服务内部仍使用
users.id关联会话、消息、群成员、设备和在线状态。 - 前端登录后通过接口换取 IM token,后续 IM HTTP 和 WebSocket 都使用 IM token。
推荐架构
text
前端
-> 用户管理服务登录接口
-> 获得用户管理服务 access_token
-> flow-talk-server /api/auth/external
-> flow-talk-server 调用户管理服务校验接口
-> flow-talk-server 同步内部 users
-> flow-talk-server 返回 IM JWT
-> 前端使用 IM JWT 调 IM 接口和 WebSocket核心边界:
- 前端不能把用户资料直接传给 IM 服务并让 IM 信任。
- IM 服务必须通过用户管理服务接口校验
access_token。 - IM 服务只信任用户管理服务返回的用户 ID、昵称、头像和状态。
- 后续 IM 权限判断只依赖内部
users.id。
接口清单
1. 用户管理服务:登录接口
由用户管理服务提供,前端调用。
text
POST /api/auth/login请求示例:
json
{
"username": "zhangsan",
"password": "******"
}响应示例:
json
{
"access_token": "user-center-access-token",
"expires_in": 7200
}说明:
- 该接口不由
flow-talk-server实现。 - IM 前端可以复用现有用户管理系统登录页,也可以由用户管理系统跳转回来。
2. 用户管理服务:Token 校验和用户资料接口
由用户管理服务提供,flow-talk-server 调用。
text
GET /api/users/me
Authorization: Bearer <user-center-access-token>成功响应:
json
{
"id": "10001",
"username": "zhangsan",
"nickname": "张三",
"avatar_url": "https://example.com/avatar.png",
"status": "enabled"
}失败响应建议:
| 场景 | HTTP |
|---|---|
| token 缺失 | 401 |
| token 无效或过期 | 401 |
| 用户被禁用 | 403 |
| 用户不存在 | 404 |
| 用户管理服务异常 | 5xx |
3. IM 服务:外部登录换取 IM Token
由 flow-talk-server 提供,前端调用。
text
POST /api/auth/external
Content-Type: application/json请求示例:
json
{
"provider": "user-center",
"access_token": "user-center-access-token"
}成功响应:
json
{
"code": 200,
"data": {
"user": {
"id": 1,
"external_id": "user-center:10001",
"username": "zhangsan",
"nickname": "张三",
"avatar_url": "https://example.com/avatar.png",
"auth_source": "external",
"status": 1
},
"token": "flow-talk-jwt"
},
"message": "登录成功"
}说明:
provider是服务端白名单,例如user-center。access_token是用户管理服务签发的 token。- 返回的
token是 IM 服务自己的 JWT。 - 后续 IM 请求不能继续使用用户管理服务 token。
时序流程
text
1. 前端调用用户管理服务登录接口
2. 用户管理服务返回 access_token
3. 前端调用 flow-talk-server POST /api/auth/external
4. flow-talk-server 根据 provider 找到用户管理服务配置
5. flow-talk-server 调用户管理服务 GET /api/users/me
6. 用户管理服务返回当前用户资料和状态
7. flow-talk-server 按 external_id 查找或创建内部 users
8. flow-talk-server 签发 IM JWT
9. 前端保存 IM JWT
10. 前端使用 IM JWT 调用会话、消息、设备、WebSocket 等接口字段映射
| 用户管理服务字段 | IM 用户字段 | 说明 |
|---|---|---|
id | external_id | 建议加 provider 前缀,例如 user-center:10001 |
username | username | 用于账号展示和唯一约束 |
nickname | nickname | 用于聊天展示 |
avatar_url | avatar_url | 用于头像展示 |
status | status | enabled 映射为 1,禁用映射为 0 或直接拒绝登录 |
external_id 必须稳定,不建议使用手机号、邮箱、昵称等可变字段。
内部用户同步策略
IM 服务收到用户管理服务资料后,按以下策略处理:
- 使用
external_id = provider + ":" + user_center_id查询users。 - 如果存在,刷新昵称、头像和启用状态。
- 如果不存在,创建一条
auth_source = external的内部用户。 - 返回内部用户并签发 IM JWT。
不要在同步时改动:
- 内部
users.id - 历史消息
sender_id - 会话成员
conversation_members.user_id
原因:IM 历史数据必须长期绑定内部用户 ID。
鉴权边界
前端需要保存两个不同 token 的语义:
| Token | 来源 | 用途 |
|---|---|---|
用户管理服务 access_token | 用户管理服务 | 只用于调用 /api/auth/external |
| IM JWT | flow-talk-server | 用于所有 IM HTTP 接口和 WebSocket |
IM HTTP 请求:
text
Authorization: Bearer <flow-talk-jwt>IM WebSocket:
text
ws://127.0.0.1:8080/api/ws?token=<flow-talk-jwt>&device_id=<device_id>错误处理建议
flow-talk-server 对外建议保持稳定错误语义:
| 用户管理服务返回 | IM 对前端返回 |
|---|---|
| 401 token 无效 | 401 或 400,提示重新登录 |
| 403 用户禁用 | 403,提示用户已禁用 |
| 404 用户不存在 | 401 或 400,提示登录态无效 |
| 5xx 服务异常 | 502 或 503,提示用户服务暂不可用 |
| 超时 | 504 或 503,提示稍后重试 |
当前项目已有基础错误映射,真实接入时建议把用户管理服务异常和 token 无效区分开,方便前端展示不同提示。
安全要求
- IM 服务不得信任前端传入的用户 ID、昵称、头像。
- IM 服务不得把用户管理服务
access_token写入数据库。 - 日志中不得打印完整
access_token或 IM JWT。 provider必须是服务端白名单。- 用户管理服务接口建议使用 HTTPS 或内网可信链路。
- IM 服务调用用户管理服务必须设置超时时间。
- 用户被禁用时不能换取新的 IM JWT。
最小联调
当前项目已有 demo provider,可以先用它验证外部登录链路:
bash
curl -X POST http://127.0.0.1:8080/api/auth/external \
-H "Content-Type: application/json" \
-d '{"provider":"demo","access_token":"external-user-001"}'预期:
- 返回 IM JWT
- 返回
user.auth_source = external users.external_id = demo:external-user-001
真实用户管理服务接入时,把 provider 从 demo 换成 user-center,并让 IM 服务通过接口调用用户管理服务校验 token。