必须嵌入jwt.registeredclaims才能校验过期时间,否则exp/iat/nbf等字段被忽略导致过期检查失效;正确做法是结构体内嵌jwt.registeredclaims且expiresat需用jwt.newnumericdate包装。

JWT Claims 必须嵌入 jwt.RegisteredClaims 才能校验过期时间
直接用 jwt.MapClaims 或自定义 struct 但不嵌入 jwt.RegisteredClaims,会导致 exp、iat、nbf 等字段被忽略——jwt.ParseWithClaims 不会报错,但过期检查完全失效。这是线上鉴权绕过的高发原因。
正确做法是定义结构体并显式内嵌:
type Claims struct {
UserID uint `json:"user_id"`
Role string `json:"role"`
jwt.RegisteredClaims
}
注意:ExpiresAt 字段名必须大写首字母,且赋值必须用 jwt.NewNumericDate(time.Now().Add(...));传 time.Now().Unix() 或字符串会静默失败。
权限校验不能只靠中间件一次解析就结束
JWT 解析成功 ≠ 用户有权限。中间件只负责身份可信(signature + exp + issuer),权限判断必须分层做:
- 基础角色白名单:如
requireRole("admin"),适合管理后台路由 - 细粒度权限字符串:Token 中带
perms: []string{"user:read", "order:write"},中间件比对"order:delete"是否在列表中 - 资源级校验:即使 Token 有
order:write,删除订单前仍要查 DB 确认该用户是否拥有该订单所有权(防止 ID 滥用)
别把权限逻辑全塞进中间件——它只该做「我能信你吗」,不该做「你能动这个数据吗」。
keyfunc 必须动态返回密钥并校验算法与长度
jwt.ParseWithClaims 的第三个参数是 jwt.Keyfunc,不是固定字符串或字节切片。常见错误包括:
使用 uber-go/dig 在 Golang 中实现依赖注入——基于反射容器,提供 Provide/Invoke、dig.In/dig.Out 参数与结果对象,支持命名依赖等
- 直接返回
[]byte("secret"):密钥短于 32 字节时,HS256 会 panic 报crypto/hmac: invalid key size - 不校验
token.Method:攻击者可篡改 header 的alg字段为none,绕过签名验证 - 硬编码密钥:生产环境必须从
os.Getenv("JWT_SECRET")或 secret manager 加载
安全的 keyfunc 示例:
func(key *jwt.Token) (interface{}, error) {
if _, ok := key.Method.(*jwt.SigningMethodHMAC); !ok {
return nil, fmt.Errorf("unexpected signing method: %s", key.Header["alg"])
}
secret := os.Getenv("JWT_SECRET")
if len(secret)
<h3>context 里存用户数据,但别存敏感字段</h3>
<p>验证通过后,用 <code>context.WithValue(r.Context(), key, value)</code> 注入 <code>UserID</code>、<code>Role</code> 即可,不要塞密码哈希、手机号、完整 Token 字符串等。</p>
<p>下游 handler 应始终通过 <code>ctx.Value(key)</code> 获取,而不是重新解析 Token —— 既避免重复开销,也防止因 header 被篡改导致两次解析结果不一致。</p>
<p>特别注意:<code>ctx.Value</code> 返回的是 <code>interface{}</code>,必须做类型断言并判空,否则 panic:</p>
<pre class="brush:php;toolbar:false;">if userID, ok := ctx.Value("user_id").(uint); !ok {
return errors.New("invalid user_id in context")
}
真正容易被忽略的点是:JWT 是静态凭证,用户状态(如是否被禁用、角色是否变更)可能已更新。敏感操作前,仍需查库确认实时状态,不能无条件信任 Token 内容。
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!










