JWT签名密钥必须通过环境变量(如JWT_SECRET_KEY)注入且启动时校验非空,禁止硬编码;解析时须显式启用exp/iat/iss校验并限制算法,防止重放与伪造。

JWT签名密钥必须用环境变量管理,不能硬编码
硬编码密钥(比如直接写 jwt.SigningMethodHS256 配合字符串常量)会导致密钥泄露风险,且无法在不同环境切换。微服务部署时,密钥必须通过环境变量注入,例如 JWT_SECRET_KEY,并在启动时校验非空。
- 使用
os.Getenv("JWT_SECRET_KEY")读取,启动失败时 panic 提示缺失 - 避免用
strings.ToLower()或其他转换处理密钥——HS256 对密钥字节敏感,大小写变更等于换密钥 - 若需轮换密钥,应支持多密钥验证:先用当前密钥验签,失败再试旧密钥(通过
jwt.Parse的Keyfunc动态返回对应密钥)
解析 JWT 时必须校验 exp、iat 和 iss
仅验证签名有效远远不够。攻击者可能重放过期 token,或伪造 issuer(比如把 iss 设为测试环境值绕过生产校验)。Golang 的 jwt.Parse 默认不强制校验这些字段,必须显式启用。
- 传入
jwt.WithValidMethods([]string{"HS256"})限制算法,防止 alg=none 攻击 - 用
jwt.WithExpirationRequired()和jwt.WithIssuedAt()启用时间校验 -
iss必须与服务自身配置的 issuer 字符串严格相等(建议从环境变量读取,如JWT_ISSUER="auth-service") - 注意:
time.Now().UTC()和 token 中exp时间单位都是秒,但 Go 的time.Unix()要求传入 int64,别漏了类型转换
HTTP 中间件里提取 token 要区分 Authorization: Bearer xxx 和 query 参数 fallback
标准做法是从 Header 提取,但某些客户端(如旧版 SDK 或调试工具)可能把 token 放在 URL 查询参数里。生产环境不应默认允许后者,但可作为临时兼容开关,需明确控制。
初始化并管理阿里云SDK Go 客户端,涵盖 sync.Once 单例、goroutine 安全、endpoint 与 region 配置、VPC 端点及调试。
- 优先检查
r.Header.Get("Authorization"),按空格分割后取第二段 - 若禁用 query fallback,就不要读
r.URL.Query().Get("token")——否则会绕过 Header 校验逻辑 - 提取后立即调用
strings.TrimSpace(),避免头部带空格导致解析失败 - 解析失败时统一返回
http.StatusUnauthorized,且响应体不要暴露错误细节(如“invalid signature”),防止信息泄露
用户上下文注入要避免污染 context.Context 键名
把用户 ID、角色等塞进请求 context 是常见做法,但用自定义 struct 作键(如 type userKey struct{})容易因包重复导入导致键不匹配——看似存进去了,下游取出来却是 nil。
立即学习“go语言免费学习笔记(深入)”;
- 统一用
var UserContextKey = struct{}{}定义全局唯一键变量,放在 shared 包里 - 存入时用
context.WithValue(ctx, UserContextKey, userInfo),其中userInfo是轻量 struct(只含ID、Role、Scopes) - 下游必须用同一变量取值:
userInfo, ok := ctx.Value(UserContextKey).(UserInfo),不能自己再定义一个同名 struct - 注意:context 传递的是引用,别把整个 JWT payload 存进去——payload 可能含敏感字段,且增大内存开销
iss 设成宽泛值(如 "myapp"),结果网关层和业务层用不同 issuer,导致 token 在某一层被静默拒绝。

















