用github.com/appleboy/gin-jwt/v2最稳妥,它专为Gin设计、维护活跃、API清晰,支持Header+Cookie双模式;自行实现易漏exp/nbf校验、时钟漂移容错、Cookie安全属性及Authenticator返回结构体等关键点。

直接上结论:用 github.com/appleboy/gin-jwt/v2(注意是 v2)最稳妥,它专为 Gin 设计、维护活跃、API 清晰,且默认支持 Header + Cookie 双模式,不用自己手写中间件逻辑。
为什么不用自己写 JWT 中间件?
自己解析 token、校验签名、提取 claims、处理过期、刷新逻辑,看似简单,但容易漏掉关键点:
- 忘记验证
exp和nbf时间戳,导致过期 token 仍被接受 - 没做时钟漂移容错(
WithTimeFunc),集群节点时间不一致时频繁报错Token is expired - Cookie 模式下忽略
SameSite或Secure属性,引发 XSS 或 CSRF 风险 - 错误地把用户 ID 当作字符串返回给
PayloadFunc,导致后续IdentityKey提取失败
Authenticator 函数必须返回结构体,不能只返回 ID
这是最常踩的坑。很多开发者在登录验证后直接 return userID, nil,结果中间件在调用 PayloadFunc 时 panic —— 因为 PayloadFunc 默认从返回值里反射取 GetUid() 或 ID 字段,而字符串没有这些方法。
正确做法是定义一个用户结构体,并确保字段可导出:
type User struct {
ID uint `json:"id"`
Username string `json:"username"`
Role string `json:"role"`
}
<p>func (u *User) GetId() interface{} { return u.ID } // 注意:v2 要求实现 GetId() 方法</p><div class="aritcle_card flexRow">
<div class="artcardd flexRow">
<a class="aritcle_card_img" href="/xiazai/gongju/2602" title="Gin框架 1.9.0"><img
src="https://img.php.cn/upload/manual/001/589/237/6a731f5b72949207.png" alt="Gin框架 1.9.0" ></a>
<div class="aritcle_card_info flexColumn">
<a href="/xiazai/gongju/2602" title="Gin框架 1.9.0">Gin框架 1.9.0</a>
<p>Gin框架 1.9.0版本源码包下载,版本号 1.9.0,适合需要 sonic JSON 支持、路由修复和内容协商改进的 Go Web 开发场景。</p>
</div>
<a href="/xiazai/gongju/2602" title="Gin框架 1.9.0" class="aritcle_card_btn flexRow flexcenter"><b></b><span>下载</span> </a>
</div>
</div><p>Authenticator: func(c *gin.Context) (interface{}, error) {
var login struct {
Username string <code>form:"username" json:"username"</code>
Password string <code>form:"password" json:"password"</code>
}
if err := c.ShouldBind(&login); err != nil {
return nil, jwt.ErrMissingLoginValues
}</p><pre class="brush:php;toolbar:false;">// 查库或调用 auth service
user, err := findUser(login.Username, login.Password)
if err != nil || user == nil {
return nil, jwt.ErrFailedAuthentication
}
return user, nil // ← 必须是 struct 指针,不是 string/int}
Timeout 和 MaxRefresh 不是“有效期”,而是“签发后多久失效”和“多久内允许刷新”
这两个字段控制的是 token 的生命周期策略,但语义容易误解:
-
Timeout: time.Hour→ 生成的 access token 的exp是签发时刻 + 1 小时 -
MaxRefresh: time.Hour * 24→ refresh token 最多允许在签发后 24 小时内调用/refresh接口换新 token - 它们不影响已签发 token 的实际过期时间,只约束签发行为
如果你希望用户登录后 7 天内免密续期,就设 MaxRefresh: time.Hour * 24 * 7;但要注意:这不代表 token 永不过期,只是“还能刷新”的窗口期更长。
生产环境必须关掉 SendCookie 或严格配置 CookieHTTPOnly
开发时开 SendCookie: true 很方便,但上线后若未设 CookieHTTPOnly: true 和 CookieSecure: true(HTTPS 环境下),前端 JS 就能读取 cookie,极大增加 XSS 泄露风险。
推荐配置组合:
SendCookie: true, CookieHTTPOnly: true, CookieSecure: true, // 仅 HTTPS 传输 CookieSameSite: http.SameSiteStrictMode,
如果前后端分离走 Header 模式(如 Authorization: Bearer xxx),干脆设 SendCookie: false,彻底规避 cookie 相关风险。

















