Gateway 如何把用户 ID 透传给下游服务
在微服务项目中,用户请求通常都会先经过 Gateway,再由 Gateway 转发到具体的业务服务。
但这里会有一个问题:
下游服务怎么知道当前请求到底是谁发起的?
例如用户调用退出登录接口时,认证服务必须知道:
当前退出的是哪个用户?
这时候,就需要 Gateway 将当前登录用户的 ID 传给下游服务。
一、为什么要透传用户 ID?
用户登录以后,请求通常会携带 Token。
例如:
Authorization: Bearer xxx
Gateway 可以通过这个 Token 获取当前登录用户 ID。
假设:
userId = 10001
但是请求被转发到认证服务之后,认证服务本身并不知道这个 10001。
例如:
客户端
↓
Gateway
↓
认证服务
如果认证服务要执行:
退出登录
修改密码
查询个人信息
发布笔记
这些业务都需要知道当前用户是谁。
因此 Gateway 在完成登录和权限校验以后,可以把用户 ID 一起传给下游服务。
二、用户 ID 怎么传?
微服务之间本身就是通过 HTTP 通信。
所以最简单的一种方式就是:
把用户 ID 放到 HTTP Header 中。
原来的请求:
Authorization: Bearer xxx
经过 Gateway 之后,可以增加:
userId: 10001
最终转发给下游服务的请求就相当于:
Authorization: Bearer xxx
userId: 10001
下游服务只需要从请求头中获取 userId 即可。
三、Gateway 如何知道用户 ID?
请求首先会经过 Sa-Token。
之前我们已经完成了:
Token
↓
登录校验
↓
权限校验
如果校验成功,说明当前请求是一个合法请求。
Gateway 就可以通过 Sa-Token 获取当前用户:
Token
↓
Sa-Token
↓
loginId
↓
userId
例如:
userId = 10001
然后 Gateway 再把这个 ID 放进 Header。
四、为什么要在鉴权之后再传?
Gateway 中实际上存在多个过滤器。
其中 Sa-Token 的过滤器会先执行,负责:
登录校验
权限校验
然后才执行用户 ID 透传过滤器。
因此请求流程是:
请求进入 Gateway
↓
Sa-Token 过滤器
↓
登录 / 权限校验
↓
校验通过
↓
用户 ID 透传过滤器
↓
获取 userId
↓
写入 Header
↓
转发下游服务
这样可以保证:
只有通过鉴权的请求,才会进入后续用户 ID 处理流程。
文中的 SaReactorFilter 优先于自定义的 AddUserId2HeaderFilter 执行,因此用户 ID 透传发生在鉴权之后。
五、用户 ID 透传的业务流程
假设用户 10001 请求退出登录接口。
第一步,客户端携带 Token:
Authorization: Bearer abc123
第二步,请求进入 Gateway:
客户端
↓
Gateway
第三步,Sa-Token 校验 Token。
如果 Token 有效:
Token
↓
解析当前用户
↓
userId = 10001
第四步,Gateway 修改请求头:
userId: 10001
第五步,请求继续转发:
Gateway
↓
认证服务
认证服务最终收到:
userId = 10001
于是认证服务就知道:
当前需要执行退出登录操作的是用户 10001。
六、如果用户没有登录怎么办?
还有一种情况:
发送验证码
登录
这些接口本来就不需要登录。
因此请求可能根本没有 Token。
这时候 Gateway 获取不到用户 ID,也不应该报错。
处理方式就是:
获取用户 ID
↓
失败
↓
说明可能是无需登录接口
↓
不添加 userId
↓
继续转发
所以这种设计既支持:
已登录请求 → 携带 userId
也支持:
匿名请求 → 正常转发
文中的过滤器也是这样处理的:如果获取不到登录用户 ID,就不修改请求,直接继续执行过滤器链。
七、下游服务怎么使用?
下游服务只需要从 Header 中读取:
userId
例如:
userId = 10001
后续业务就可以直接使用这个 ID。
于是整个系统的职责就非常清晰:
Gateway
负责:
Token 校验
获取用户 ID
用户 ID 透传
下游服务
负责:
拿到 userId
执行真正的业务逻辑
文中的退出登录接口就是直接从请求头读取 Gateway 传递过来的 userId。
八、完整业务流程
最终整个链路可以概括成:
用户登录
↓
获得 Token
↓
客户端携带 Token 请求
↓
Gateway
↓
Sa-Token 校验登录状态
↓
校验权限
↓
获取当前 userId
↓
将 userId 写入 Header
↓
Gateway 转发请求
↓
下游服务读取 userId
↓
执行具体业务
例如:
Authorization: Bearer xxx
↓
Gateway
↓
解析得到 userId = 10001
↓
Header 添加 userId: 10001
↓
认证服务
↓
知道当前操作用户是 10001
九、总结
用户 ID 透传解决的核心问题就是:
Gateway 知道当前用户是谁,但下游服务不知道,所以需要把用户身份继续传递下去。
整个方案可以总结为:
Token
↓
Gateway 解析用户
↓
得到 userId
↓
写入 Header
↓
透传给下游服务
这样下游服务就不需要重复解析 Token,只需要直接获取当前用户 ID,就可以完成后续业务处理。