发布于2026-07-20 阅读(0)
扫一扫,手机访问
先说几个核心判断:JWT(JSON Web Token)是Go语言实现无状态认证的基石,但直接套用示例代码,大概率会在生产环境出问题。密钥硬编码、exp校验失败、中间件透传丢失上下文、Token被重放——这些都不是“跑通就行”的小麻烦。

JWT的核心结构,说白了就是Header.Payload.Signature这三部分。Header声明类型和算法,Payload里放声明(注意,这只是Base64URL编码,不是加密),Signature确保完整性。数据都是明牌,但怎么用,区别很大。
你猜最容易栽在哪儿?是调用 jwt.ParseUnverified() 解析payload后,手动判断 exp。这等于主动放弃签名验证,攻击者可以任意修改 user_id 或 exp,伪造一个看起来合法的token。
正确的做法始终是:用 jwt.ParseWithClaims(),并且确保 KeyFunc 返回的密钥类型跟签名算法匹配。具体来说:
[]byte,不能传字符串。从环境变量读取时,要用 []byte(os.Getenv("JWT_SECRET"))。KeyFunc 需要返回 *rsa.PublicKey,而私钥签名时要用对应的 *rsa.PrivateKey。jwt.ParseWithClaims() 会静默失败,token.Valid 为false,但 err 可能是nil。这很要命,因为代码如果只检查 err,就会误以为token有效。很多中间件只做了解析,没检查 token.Claims.(jwt.MapClaims)["user_id"] 是否存在,或者忽略了 token.Header["alg"] 是否被篡改为 none(这是一个已知漏洞)。
关键逻辑一步都不能省:
strings.TrimPrefix(tokenStr, "Bearer ") 剥离前缀,再用 strings.TrimSpace() 清空两端空格。err == nil 和 token.Valid == true,二者缺一不可。c.Request.Context()(Gin框架)或 r.Context()(net/http),而不是 c.Set() 这类框架内部存储,避免handler里取不到。UserClaims 结构体,务必实现 Valid() 方法来校验 exp、nbf 等标准字段。把refresh token也做成JWT是一个典型误区。JWT无法主动作废,一旦泄露,就等于给了攻击者一张长期通行证。
生产环境应该这么干:
refresh:,value存关联的user_id和过期时间。jti,存其SHA256哈希到Redis,并设置跟refresh token一样的TTL。DEL 这个key,做到一用即废。exp 控制在15–60分钟,refresh token的TTL控制在7天以内。最容易被忽略的是时钟偏移处理。服务端和客户端系统时间差超过1秒,exp 就会校验失败。别调服务器时间,改用 jwt.WithLeeway(5 * time.Second) 传入 ParseWithClaims 的选项参数,这才是省心又靠谱的做法。
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
售后无忧
立即购买>office旗舰店
正版软件
正版软件
正版软件
正版软件
正版软件
1
2
3
7
8