身份验证与速率限制中间件
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 反馈 — 无需本地设置。
此课程中的所有课时
- HTTP 中间件链基础
- 日志记录与请求 ID 中间件
- 身份验证与速率限制中间件
- CORS 与 panic 恢复中间件