Go mod 好菜系列 - 0x08 jwt 这张票该怎么发和怎么验

更模块化地聊 jwt:签发、校验、claims、过期、刷新和中间件实践,看看它为什么高频,又为什么不能被神化。

只要项目里一提到登录态,JWT 基本迟早会出现。它常见到一种程度,很多人会下意识把“认证方案”和“JWT”直接画等号。但实际上,JWT 只是常见方案之一,而且还是一个很容易被用得过度自信的方案。

先别急着吹 JWT,先想清楚它在解决什么

它本质上是在解决“服务端怎么识别调用方身份”这件事。简单说:

  • 服务端签一个 token 给客户端
  • 客户端后续请求带着它来
  • 服务端验证签名和 claims

这样就不需要每次都去查一次 session 存储,至少在某些场景下会更轻一点。

常见 Go JWT 库会长什么样

现在社区里比较常见的是 github.com/golang-jwt/jwt/v5 这类库。重点不在库名字,而在它把 JWT 的几个关键步骤拆得比较清楚:

  • 定义 claims
  • 签发 token
  • 解析 token
  • 验证签名和过期

签发 token 的最小示例

claims := jwt.MapClaims{
    "user_id": 1,
    "role":    "admin",
    "exp":     time.Now().Add(2 * time.Hour).Unix(),
}

token := jwt.NewWithClaims(jwt.SigningMethodHS256, claims)
tokenString, err := token.SignedString([]byte("secret-key"))

这里最重要的不是“能不能签出来”,而是你往 claims 里放了什么。别因为它是你自己签的,就把敏感信息一股脑塞进去。

校验 token 也不只是能 parse 就算完

parsed, err := jwt.Parse(tokenString, func(token *jwt.Token) (interface{}, error) {
    return []byte("secret-key"), nil
})
if err != nil {
    return err
}

if !parsed.Valid {
    return errors.New("invalid token")
}

很多人一开始会把“能解析成功”和“这个 token 合法”混成一回事。实际上你还得关心签名方法是不是你预期的、claims 里有没有必要字段、过期时间是不是有效。

自定义 claims 往往更实用

type UserClaims struct {
    UserID int64  `json:"user_id"`
    Role   string `json:"role"`
    jwt.RegisteredClaims
}

这样比全程 MapClaims 更可控,尤其是字段越来越多的时候。

JWT 在项目里最常见的落点:中间件

func AuthMiddleware() gin.HandlerFunc {
    return func(c *gin.Context) {
        auth := c.GetHeader("Authorization")
        if auth == "" {
            c.AbortWithStatusJSON(401, gin.H{"error": "unauthorized"})
            return
        }

        // 这里解析和校验 token
        c.Next()
    }
}

模块层面最关键的理解其实是:JWT 库本身只是工具,真正的工程接入点往往是在中间件里。

JWT 最容易让人误判的地方

  • 觉得有了 JWT 就“无状态且无敌”
  • 忘了 token 失效、刷新、注销怎么做
  • claims 塞太多东西
  • 把权限判断全寄托在 token 里,不再结合数据库和业务状态

JWT 能解决的是身份票据问题,不是整个安全体系问题。

什么时候适合用 JWT

  • 前后端分离接口服务
  • 多服务间需要传递调用身份
  • 希望减少传统 session 存储依赖

如果你的系统本身就是强会话、强状态、强撤销控制的,JWT 不一定天然就是最顺手的方案。

小结

JWT 这道菜很常见,但最好别把它吃成信仰:

  • 它适合解决身份票据传递,不等于解决所有认证问题
  • 签发、解析、claims 设计、中间件接入是核心
  • 别把 token 当权限真理
  • 刷新、注销、失效策略必须一开始就想

下一篇我们讲 sqlx。如果你对 ORM 不完全放心,但又嫌原生 database/sql 太原始,那这道菜就很值得看看。

Read more

Harness Engineering:从驾驭模型到构建 AI 工厂

Harness Engineering:从驾驭模型到构建 AI 工厂

2026 年,AI 编程工具的竞争焦点发生了根本性转变:决定 AI 助手好不好用的,不再是模型本身,而是包裹在模型外面的那层"Harness"。同一个模型,在不同的 Harness 下,性能差距可以达到 78% vs 42%。 这篇文章将带你深入了解 Harness Engineering——这个正在重新定义 AI 工程实践的新兴领域。 一、什么是 Harness Engineering? Harness 的字面意思是"马具/缰绳"——用来驾驭一匹强壮但不受控的马。在 AI 语境下,Harness 就是 LLM 之外的一切:工具定义、记忆系统、权限模型、反馈循环、文档规范、多

By Fuyu Jia

Claude Code CLI + Ralph:让 AI 自动完成大型编程任务的终极方案

TL;DR 当你的编程任务大到一个 AI 对话窗口装不下时,Ralph 会帮你把任务拆成小块,让 Claude Code CLI 一个接一个地自动完成——每轮都用全新的上下文窗口,不会越写越糊涂。 一、什么是 Ralph? Ralph 是一个开源项目(GitHub 16k+ Stars),基于 Geoffrey Huntley 提出的 "Ralph Pattern" 构建。它的核心理念很简单: 不要让 AI 在一个漫长的会话里做完所有事情,而是把大任务拆成小故事,每个故事用一个全新的 AI 实例来完成。 这解决了 AI 编程中最常见的痛点——上下文窗口耗尽。当对话越来越长,AI 的输出质量会明显下降。Ralph 通过「每轮一个新实例」的方式,

By Fuyu Jia