公司动态

如何正确签发JWT令牌?jwtauth的Encode与exp/iat声明实战指南

📅 2026/8/24 17:00:35
如何正确签发JWT令牌?jwtauth的Encode与exp/iat声明实战指南
如何正确签发JWT令牌jwtauth的Encode与exp/iat声明实战指南【免费下载链接】jwtauthJWT authentication middleware for Go HTTP services项目地址: https://gitcode.com/gh_mirrors/jw/jwtauthjwtauth 是一款面向 Go HTTP 服务的轻量级 JWT 认证中间件。本文将带你用 jwtauth 的Encode方法正确签发 JWT 令牌并讲透exp过期时间与iat签发时间两个关键声明的设置技巧帮你避开 401 陷阱快速搭建安全的接口认证。一、jwtauth 是什么Go 语言的 JWT 认证中间件 jwtauth解决的是一个非常具体的问题从 HTTP 请求里取出 JWT 令牌 → 解码 → 验证签名 → 检查是否过期然后把结果放进请求上下文供后续处理函数使用。它的几个特点对新手非常友好特点说明路由无关可搭配任意 Go HTTP 路由使用如 chi不绑定特定框架依赖极简唯一的第三方依赖是lestrrat-go/jwx这个底层 JWT 库见 go.mod核心代码短小全部逻辑集中在 jwtauth.go 一个文件里读完即懂默认查找顺序先从Authorization: BEARER T请求头找令牌再找jwtCookie 想快速体验先克隆仓库git clone https://gitcode.com/gh_mirrors/jw/jwtauth核心文件就三样jwtauth.go源码、_example/main.go完整示例、jwtauth_test.go测试用例。二、JWT 签发与校验的 3 个核心步骤 在 jwtauth 中一次完整的认证流程只有三步创建JWTAuth实例—— 调用jwtauth.New(算法, 签名密钥, 验签密钥, 校验选项...)算法支持 HS256、RS256 等签发令牌—— 调用Encode(claims)方法把声明claims签名编码成 JWT 字符串验证令牌—— 请求进来后Verifier中间件自动完成查找、解码、验签、校验Authenticator中间件对无效令牌直接返回 401。// 创建 JWTAuth 实例HS256 对称加密secret 为密钥 tokenAuth : jwtauth.New(HS256, []byte(secret), nil, jwt.WithAcceptableSkew(30*time.Second)) // 签发一个令牌 _, tokenString, _ : tokenAuth.Encode(map[string]interface{}{user_id: 123})签发端和验证端只要算法一致、密钥一致就能互相打通。三、Encode 方法实战3 行代码签发一个 JWT 令牌 ✍️Encode的签名很简单源码见 jwtauth.gofunc (ja *JWTAuth) Encode(claims map[string]interface{}) (t jwt.Token, tokenString string, err error)传入一个声明字典返回签好名的 JWT 字符串。一个带用户身份的完整示例claims : map[string]interface{}{user_id: 123} jwtauth.SetIssuedNow(claims) // iat签发于当前时间 jwtauth.SetExpiryIn(claims, time.Hour) // exp1小时后过期 _, tokenString, err : tokenAuth.Encode(claims)两个容易踩的坑声明类型要合法Encode会对每个 claim 做类型检查。例如jtiJWT ID必须传字符串如果传成数字1Encode会直接返回错误——这一点在 jwtauth_test.go 的TestEncodeClaims用例中被明确验证过。只验签的实例不能签发非对称加密如 RS256场景下如果实例只配置了公钥verifyKey而没有私钥Encode会报错Decode正常工作。适合签发服务持有私钥、业务服务只用公钥验签的分层架构测试用例TestSimpleRSAVerifyOnly演示了这一点。四、exp 与 iat 声明时间辅助函数全解 ⏰exp和iat是 JWT 规范里的注册声明Registered Claims它们决定了令牌何时生效、何时作废也是新手最容易写错的地方。jwtauth 专门提供了一组辅助函数让你不用手动算时间戳辅助函数作用典型用法EpochNow()当前 UTC Unix 时间戳手动计算时间基准ExpireIn(d)计算现在 时长 d的过期时间戳ExpireIn(5 * time.Minute)SetIssuedNow(claims)将iat设为当前时间签发时自动填充SetIssuedAt(claims, tm)将iat设为指定时间补签、迁移场景SetExpiryIn(claims, d)将exp设为现在 d最常用的签发写法SetExpiry(claims, tm)将exp设为指定时间令牌与业务周期绑定为什么时间很重要验证阶段jwtauth会把底层 JWT 库的原始错误归一化成几个固定错误见ErrorReason函数错误常量触发场景401 响应体ErrExpired令牌超过exp过期时间token is expiredErrIATInvalidiat声明校验失败未来时间token iat validation failedErrNBFInvalid令牌到了nbf时间还没生效token nbf validation failedErrUnauthorized签名错误、算法不匹配等token is unauthorized宽容时间Skew给时钟误差留余地服务器之间时钟往往有几十秒误差。如果不处理刚过期的令牌在另一台机器上可能还活着或者刚签发的令牌被误判失效。jwtauth 支持传入校验选项来设置容差窗口tokenAuth jwtauth.New(HS256, []byte(secret), nil, jwt.WithAcceptableSkew(30*time.Second)) // 允许 30 秒偏差jwtauth_test.go 里有一组很直观的测试过期 29 秒的令牌在 30 秒容差内仍然放行返回 200过期 31 秒则被拒绝返回 401。生产环境建议设置 30 秒左右的 skew。五、返回 401对照这张清单排查常见错误 ✅以下行为全部来自 jwtauth_test.go 中的真实测试用例可以直接当作排查对照表请求场景状态码响应内容未携带令牌401no token found令牌格式错误Bearer asdf401token is unauthorized用错误的密钥签发401token is unauthorized算法不匹配HS256 服务收到 HS512 令牌401token is unauthorized令牌已过期超出 skew 窗口401token is expired有效令牌200进入受保护接口排查三问密钥和算法对吗签发端和验证端的算法、密钥必须完全一致jwtauth明确拒绝算法不匹配的令牌ErrAlgoInvalid时间对吗检查exp是否已过期、iat是否被设成了未来时间令牌位置对吗默认从Authorization: BEARER T头或jwtCookie 中查找大小写不敏感Bearer/BEARER/bearer均可如需从 URL 查询参数取可用TokenFromQuery自定义Verify中间件的查找序列。六、完整示例从签发令牌到访问受保护路由 仓库自带一个可运行的最小示例位于 _example/main.go结构非常清晰func router() http.Handler { r : chi.NewRouter() r.Group(func(r chi.Router) { r.Use(jwtauth.Verifier(tokenAuth)) // 第1步查找并验证令牌 r.Use(jwtauth.Authenticator(tokenAuth)) // 第2步拒绝无效令牌 r.Get(/admin, func(w http.ResponseWriter, r *http.Request) { _, claims, _ : jwtauth.FromContext(r.Context()) w.Write([]byte(fmt.Sprintf(protected area. hi %v, claims[user_id]))) }) }) r.Get(/, func(w http.ResponseWriter, r *http.Request) { w.Write([]byte(welcome anonymous)) // 公开路由 }) return r }运行后效果摘自_example/main.go头部注释$ curl http://localhost:3333/ welcome anonymous $ curl -HAuthorization: BEARER eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VyX2lkIjoxMjN9.PZLMJBT9OIVG2qgp9hQr685oVYFgRgWpcSPmNcw6y7M \ http://localhost:3333/admin protected area. hi 123注意Authenticator只是默认实现返回的是纯文本 401。实际项目中通常参考 jwtauth.go 里它的写法改成自定义 JSON 错误响应——源码只有十几行改起来毫无压力。七、签发 JWT 令牌的最佳实践清单 最后把本文要点浓缩成一张签发前检查清单✅必须设置exp用SetExpiryIn(claims, d)给令牌一个明确的有效期宁可短一点、让客户端刷新✅建议设置iat用SetIssuedNow(claims)填充签发时间方便排查问题✅设置时钟容差jwt.WithAcceptableSkew(30*time.Second)吸收服务器间时钟误差✅密钥管理单机服务用 HS256 对称密钥多服务协作用 RS256签发方持私钥、验证方只配公钥✅算法显式指定签发与验证两端算法必须一致jwtauth 会自动拒绝算法不匹配的令牌✅错误响应可定制复用Verifier 自定义鉴权中间件返回结构化的 401 错误。掌握Encode与exp/iat的正确用法你就完成了 JWT 认证最核心的签发环节。配合Verifier与Authenticator两个中间件一个安全、简洁的 Go 接口认证体系就搭建完成了。【免费下载链接】jwtauthJWT authentication middleware for Go HTTP services项目地址: https://gitcode.com/gh_mirrors/jw/jwtauth创作声明:本文部分内容由AI辅助生成(AIGC),仅供参考