Gin默认不带JWT支持因其是轻量框架,不内置认证逻辑;需手动引入golang-jwt/jwt(替代有安全问题的jwt-go);写中间件须处理Access/Refresh Token校验与刷新,并规范Payload结构及密钥管理。

为什么 Gin 默认不带 JWT 支持
Gin 本身是轻量 HTTP 框架,不内置任何认证逻辑,jwt-go 或 golang-jwt/jwt 都得手动引入。官方没绑定 JWT,是因为认证方式太多(Session、OAuth2、API Key),硬塞进去反而增加耦合和维护成本。
实际项目里,你得自己选库、写中间件、处理签发/校验/刷新逻辑。别指望 gin.Default() 自动帮你挂上 AuthMiddleware —— 它连 net/http 的基础路由都没封装完。
用 golang-jwt/jwt 替代 jwt-go 的必要性
jwt-go 已归档且存在已知安全问题(如 CVE-2020-26160),社区推荐迁移到 golang-jwt/jwt。新库默认禁用弱签名算法(如 none),强制检查 kid 和 alg 字段,还修复了时序攻击隐患。
- 导入路径必须是
github.com/golang-jwt/jwt/v5(注意v5) -
jwt.ParseWithClaims的第三个参数类型从func() jwt.Claims变成jwt.Claims实例 - 校验时必须显式调用
token.Valid,不能只靠err == nil - 过期时间字段名仍是
exp,但解析失败时错误信息更明确,比如"token is expired"
如何写一个不漏掉 Refresh Token 的中间件
单纯校验 Authorization: Bearer xxx 只解决登录态验证,但生产环境必须支持 Token 刷新。常见错误是把 Refresh Token 存在 Cookie 里却忘了设 HttpOnly 和 SameSite=Strict,或者校验时没比对 jti 防重放。
立即学习“go语言免费学习笔记(深入)”;
中间件里至少要处理三件事:
- 从 Header 或 Cookie 提取 Access Token,用
jwt.Parse解析并校验签名、过期、issuer - 若 Access Token 过期但 Refresh Token 有效,生成新 Access Token 并返回
200 OK+ 新 token(不是重定向) - 拒绝没有
Authorization头、签名无效、exp小于当前时间、或iss不匹配的请求 - 把解析后的
claims注入c.Set("user_id", claims["sub"]),后续 handler 用c.MustGet("user_id")取值
JWT Payload 设计容易被忽略的细节
很多人直接往 map[string]interface{} 塞用户 ID 和角色,结果遇到字段名大小写不一致(UserId vs user_id)、时间戳精度丢失(time.Now().Unix() 被截断)、或没预留扩展字段导致后期改结构要全量刷 Token。
建议定义结构体并嵌入 jwt.RegisteredClaims:
type CustomClaims struct {
jwt.RegisteredClaims
UserID uint `json:"user_id"`
Role string `json:"role"`
Scopes []string `json:"scopes"`
}
这样能利用标准字段(exp, iat, iss)做自动校验,也避免手写 map 时拼错键名。生成 Token 时用 token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims),别用 jwt.MapClaims。
密钥长度别用短字符串——[]byte("my-secret") 不安全,至少 32 字节随机字节,存环境变量里读取。


















