jwt签名密钥必须用[]byte而非字符串,因hmac.new()要求字节切片;解析后须显式校验token.valid;微服务透传应避免复用authorization头;刷新应使用独立refresh_token而非延长exp;jwt无状态仅限签名验证,权限变更等需有状态机制兜底。

JWT签名密钥必须用[]byte而非字符串直接传给jwt.SigningMethodHS256
Go标准库的jwt-go(v3及以前)或golang-jwt/jwt(v4+)对密钥类型非常敏感。常见错误是把环境变量读出的字符串直接传给jwt.SigningKey,导致签名失败或验签永远不通过。
-
jwt.SigningMethodHS256内部调用hmac.New(),它要求密钥是[]byte;传入string会隐式转换但可能因编码问题出错(比如含不可见字符) - 正确做法:显式转为字节切片,例如
[]byte(os.Getenv("JWT_SECRET")),且建议在服务启动时校验密钥长度(HS256至少32字节) - 若用
golang-jwt/jwtv4+,jwt.SigningKey字段类型已是interface{},但仍推荐统一用[]byte,避免某些算法(如ES256)因类型推导失败而panic
解析token时必须显式调用token.Valid并检查err
很多开发者只做token, err := jwt.Parse(...)就认为验证完成,其实jwt.Parse只做语法解析,不校验签名、过期、白名单等。未检查token.Valid会导致伪造token绕过认证。
-
err为nil只表示token结构合法,不代表已通过签名和时间校验 - 必须额外判断:
if token != nil && token.Valid && err == nil,三者缺一不可 - 常见漏判场景:token已过期但
err为nil(因为Parse默认不校验exp),此时token.Valid为false - 若需自定义校验逻辑(如检查
iss或aud),应在jwt.Parser{ValidMethods: []string{"HS256"}}中传入jwt.WithValidMethods,并在Claims实现Valid() error
微服务间透传JWT需避免在HTTP Header中混用Authorization和自定义字段
当API网关鉴权后将用户信息透传给下游服务时,若直接把原始Authorization: Bearer xxx头转发,下游服务重复解析同一token,既增加CPU开销,又无法区分“本层鉴权”和“上游透传”。更危险的是,某些中间件会自动读取Authorization头并尝试验证,导致冲突。
Go 配置库,使用 spf13/viper — 分层优先级(flag > env >file > KV > default),提供 BindPFlag/BindPFlags、SetEnvPrefix + SetEnvKeyReplace 等功能。
- 推荐方案:网关验证成功后,剥离原始token,改用
X-User-ID、X-User-Roles等可信内部头传递必要字段 - 若必须透传原始token(如下游需按需重新验签),应改用
X-Forwarded-JWT等非标准头,明确语义,并在下游服务中禁用对该头的自动处理 - 注意:Gin/echo等框架的
ctx.Request.Header.Get("Authorization")会返回空字符串而非nil,需先用strings.HasPrefix()判断是否存在Bearer前缀,再截取token
刷新token时别用exp硬续期,而要用独立的refresh_token + 短生命周期access_token
单纯延长exp时间(比如每次请求都重签一个新token)等于放弃token失效能力,违背JWT“无状态”初衷——你无法主动使某个token作废,除非引入Redis黑名单,那就不是纯无状态了。
- 正确做法:发放一对token——短时效
access_token(如15分钟)用于常规接口,长时效refresh_token(如7天)仅用于换取新access_token -
refresh_token必须存储在服务端(如Redis),绑定用户ID+设备指纹,并在每次使用后更新或作废 - 不要把
refresh_token塞进JWT payload;它本身不该是JWT,而应是随机生成的加密字符串(如crypto/rand.Read生成32字节) - 客户端拿到新
access_token后,应丢弃旧token;服务端收到重复使用的refresh_token应立即拉黑对应设备
JWT的“无状态”是有限度的——签名验证可无状态,但权限变更、强制登出、设备管理这些必须靠有状态的配套机制兜底。别指望单靠token payload解决所有问题。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










