token验证中间件需用c.abort()终止请求,严格解析bearer token,401响应;密钥须从环境变量读取并校验;refresh token需redis存储+lua原子操作;用户信息通过c.set()注入上下文。

Token 验证中间件怎么写才不绕过校验
直接在 gin.HandlerFunc 里解析 Authorization 头、校验 JWT、注入用户信息,是最常见也最容易出错的方式。关键不是“能不能跑”,而是“有没有漏掉未授权路径”。
- 必须用
c.Abort()终止请求,不能只return—— 否则后续 handler 仍会执行 -
Authorization头格式必须严格匹配Bearer <token></token>,空格、大小写、前缀缺失都会导致解析失败 - 未携带 token 或解析失败时,统一返回
401 Unauthorized,不要混用403 - 建议把 token 解析和验证拆成两个函数:一个负责提取
tokenString,一个调用jwt.ParseWithClaims并校验exp、iss等字段
JWT 签名密钥怎么存才安全
硬编码在代码里的 signingKey 是最典型的线上事故源头。开发环境用字符串没问题,但上线必须隔离。
- 优先从环境变量读取:
os.Getenv("JWT_SECRET"),启动时校验非空,为空直接 panic - 避免用配置文件明文存储——哪怕 YAML/JSON 也容易被误提交到 Git
- 如果用 KMS 或 Vault,封装成初始化函数,在
main()开头调用,失败就退出,不带密钥不启动服务 - 密钥长度建议 ≥32 字节;若用
HS256,短密钥易被暴力破解
如何让 token 过期后自动刷新(Refresh Token)
纯 JWT 无状态,但“自动续期”需要服务端配合维护 refresh token 的有效性,否则就退化成延长 access token 有效期,失去安全意义。
- access token 设为短时效(如 15 分钟),refresh token 单独生成、带
refresh_exp声明,存入 Redis 并设 TTL(如 7 天) - 刷新接口(如
POST /auth/refresh)需验证旧 refresh token 是否存在且未被撤销 - 每次成功刷新后,旧 refresh token 必须
DEL掉,并发请求可能撞出双 token,加 Lua 脚本原子操作更稳 - 客户端收到新 token 后,要替换本地存储,且原 access token 不再接受任何请求(服务端可维护一个短期黑名单,或依赖签名失效)
Gin 中如何把用户信息透传到业务 handler
别用全局变量或闭包捕获,Gin 的上下文 c 才是唯一可信载体。
- 校验通过后,用
c.Set("user_id", userID)和c.Set("role", role)注入,避免反复解析 token - 业务 handler 中统一用
userID, ok := c.Get("user_id").(uint64)取值,务必检查ok - 不要在中间件里修改
c.Request.Header注入用户字段——HTTP header 是只读的,改了也不生效 - 如果用了结构体封装用户信息,定义类型如
type UserClaim struct { ID uint64; Name string },解析后存c.Set("user", user),比多个字段更清晰
golang免费学习笔记(深入):立即使用
在学习笔记中,你将探索golang的核心概念和高级技巧!











