jwt验证中间件应放在网关层路由匹配之后、转发上游服务之前;须跳过/health、/metrics等免鉴权路径,禁用全局挂载,避免健康检查失败。

JWT验证中间件该放在哪一层?
网关层做JWT校验是合理且主流的做法,但必须确保它在路由匹配之后、转发上游服务之前执行。Golang里常见错误是把jwt.Parse放在反向代理前的全局中间件里,结果所有请求(包括/health、/metrics)都强制鉴权,导致健康检查失败或Prometheus抓取中断。
- 正确位置:在匹配到具体后端服务路由后,调用
http.RoundTripper前插入中间件 - 跳过路径需显式声明,比如用
skipPaths := map[string]bool{"/login": true, "/public/*": true} - 别依赖
gorilla/mux的Use方法全局挂载——它无法按路由动态启用/禁用
如何安全解析和校验JWT token?
直接用jwt.Parse而不指定Keyfunc或验证alg字段,会导致算法混淆漏洞(如RS256被降级为HS256)。Go标准库github.com/golang-jwt/jwt/v5默认不校验alg,必须手动加约束。
- 必须设置
jwt.WithValidMethod(jwt.SigningMethodHS256)或类似校验逻辑 -
Keyfunc返回的密钥不能硬编码,建议从环境变量读取并做bytes.Equal防时序攻击 - 注意
token.Valid只是语法有效,还需检查token.Claims.(jwt.MapClaims)["exp"]是否过期 - 别忽略
token.Method.Alg(),尤其当支持多算法时,要拒绝"none"或未预期算法
token怎么透传给下游微服务?
网关不光要验证,还得把可信的用户身份往下传。常见错误是原样转发原始Authorization头,导致下游重复解析或伪造风险;更糟的是把sub、role等字段塞进新header但没签名,下游无法信任。
- 推荐做法:解析后提取必要字段(如
sub、scope),构造新X-User-ID、X-User-Roles等只读头 - 避免传递原始token——除非下游明确需要且有独立校验能力
- 如果下游也用JWT,可考虑用网关私钥签发短时效的“下游token”,但会增加密钥分发复杂度
- 注意HTTP header大小限制,
X-User-Roles若含大量权限项,建议转为ID映射而非明文列表
刷新token和黑名单怎么处理?
JWT本身无状态,但业务常需要主动登出或token吊销。网关层没法靠数据库查黑名单,又不能让每个请求都查Redis——性能扛不住。
- 折中方案:用Redis缓存黑名单(
blacklist:token_id),设置TTL略长于token有效期,配合布隆过滤器前置过滤 - 刷新逻辑不应由网关实现——应由专门的
/refresh端点处理,网关只负责校验refresh token的签名和时效 - 注意
iat和nbf字段,避免刷新窗口重叠导致旧token仍可用 - 别在网关里做refresh token轮换(如生成新refresh token),这属于认证服务职责
JWT在网关层不是开箱即用的“插件”,每个环节——解析时机、算法约束、字段透传、吊销机制——都得结合业务链路仔细对齐。最容易被忽略的是下游服务对透传字段的信任边界:它们到底该信网关的X-User-ID,还是自己再验一遍原始token?这个决策会影响整个系统的安全纵深。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











