0Pricing
Go Academy · 课时

身份验证与速率限制中间件

JWT 验证与令牌桶速率限制

身份验证与速率限制中间件 是 CoddyKit 上的免费 Go Academy 课时。 这是第 3 节课,共 4 节。 你可以在下方免费阅读本课时的完整内容 — 然后在浏览器中使用内置代码编辑器和全天候 AI 导师进行实践。 这是 Go Academy 学习路径的一部分,你的进度在网页和 CoddyKit 应用中同步。 Go Academy 课程共包含 4 节课。

JWT 身份验证中间件

从 Authorization 标头中提取、解析并验证 JWT:

func JWTAuth(secret []byte) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            header := r.Header.Get("Authorization")
            if !strings.HasPrefix(header, "Bearer ") {
                http.Error(w, "missing token", 401); return
            }
            token := strings.TrimPrefix(header, "Bearer ")
            claims, err := parseJWT(token, secret)
            if err != nil {
                http.Error(w, "invalid token", 401); return
            }
            ctx := context.WithValue(r.Context(), claimsKey{}, claims)
            next.ServeHTTP(w, r.WithContext(ctx))
        })
    }
}

API 密钥身份验证

根据数据库或内存中的集合,验证标头中的 API 密钥:

func APIKeyAuth(validKeys map[string]bool) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            key := r.Header.Get("X-API-Key")
            if !validKeys[key] {
                http.Error(w, "forbidden", 403); return
            }
            next.ServeHTTP(w, r)
        })
    }
}

令牌桶限流器

结合使用 golang.org/x/time/rate 和按 IP 地址划分的限流器映射:

var limiters sync.Map

func getLimiter(ip string) *rate.Limiter {
    v, _ := limiters.LoadOrStore(ip, rate.NewLimiter(rate.Every(time.Second), 10))
    return v.(*rate.Limiter)
}

限流中间件

在中间件中检查限流器,超出限制时返回 429:

func RateLimit(next http.Handler) http.Handler {
    return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
        ip, _, _ := net.SplitHostPort(r.RemoteAddr)
        if !getLimiter(ip).Allow() {
            http.Error(w, "rate limit exceeded", 429); return
        }
        next.ServeHTTP(w, r)
    })
}

Retry-After 标头

添加 Retry-After 标头, указ明客户端在重试前应等待的秒数:

w.Header().Set("Retry-After", "1")
http.Error(w, "rate limit exceeded", 429)

基于角色的访问控制

完成身份验证后,在调用 Next 之前,从上下文声明中检查用户的角色:

func RequireRole(role string) func(http.Handler) http.Handler {
    return func(next http.Handler) http.Handler {
        return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
            claims := claimsFromContext(r.Context())
            if !claims.HasRole(role) {
                http.Error(w, "forbidden", 403); return
            }
            next.ServeHTTP(w, r)
        })
    }
}

清理限流器

旧的按 IP 地址划分的限流器会不断累积在内存中。请使用后台 goroutine 清理它们,删除最近 N 分钟内未访问过的条目。

分布式限流

进程内限流器无法跨多个实例工作。请使用 Redis 以及滑动窗口或令牌桶脚本来实现分布式限流。

429 与 503 的区别

当单个客户端受到限流时,返回 429 Too Many Requests。当整个服务过载并开始丢弃负载时,返回 503 Service Unavailable。

组合身份验证与限流

请将它们作为链中的独立中间件应用。先进行身份验证:仅对已通过身份验证的用户限流,这样就可以按用户 ID 而不是 IP 地址进行区分。

测试身份验证中间件

使用 httptest 传入有效和无效令牌,并断言设置了正确的状态码和上下文值。

快速检查

客户端超出限流限制时,限流中间件应返回哪个 HTTP 状态码?

回顾:身份验证与限流

要点:

  • JWT 中间件:提取 Bearer 令牌 → 解析 → 将声明附加到上下文
  • 使用 golang.org/x/time/rate 按 IP 地址或用户进行限流
  • 超出限制时返回 429 和 Retry-After 标头
  • 分布式限流:使用 Redis 实现多实例限流

常见问题解答

「身份验证与速率限制中间件」课时是免费的吗?

是的 — 「身份验证与速率限制中间件」的完整文本可在网页上免费阅读。要进行交互式练习(内置代码编辑器和全天候 AI 导师)并解锁 Go Academy 课程的其余内容,请升级到 CoddyKit PRO。 Go Academy 课程共包含 4 节课。

「身份验证与速率限制中间件」这节课中我会学到什么?

JWT 验证与令牌桶速率限制 你通过在浏览器中直接运行的动手代码来练习 Go Academy,全天候 AI 导师会在你学习这节课的过程中回答你的问题。

学习 Go Academy 需要有经验吗?

无需任何先前经验。CoddyKit 上的 Go Academy 课程适合初学者到高级学习者,你可以从这里开始或从头开始,按照自己的节奏学习。 这是第 3 节课,共 4 节。

「身份验证与速率限制中间件」课时需要多长时间?

大多数 CoddyKit 课程大约需要 5–10 分钟。每节课都很精短且互动,所以你能稳步进步,并在网页和应用中从离开的地方继续。

我能在这节 Go Academy 课中编写并运行代码吗?

能。每节 Go Academy 课都包含内置代码编辑器,你可以在浏览器中直接编写并运行真实代码,并获得即时 AI 反馈 — 无需本地设置。

此课程中的所有课时

  1. HTTP 中间件链基础
  2. 日志记录与请求 ID 中间件
  3. 身份验证与速率限制中间件
  4. CORS 与 panic 恢复中间件
← 返回 Go Academy