Go: Go Middleware e Autenticação JWT
Última atualização: 2026-08-26
O middleware é o “fluxo” dos microsserviços em Go — autenticação, limitação de taxa, registro de logs e recuperação; cada aspecto transversal é um componente do middleware.
Quando você precisa verificar a autenticação JWT, registrar atividades ou aplicar limites de taxa em todos os endpoints da API, o padrão de middleware permite que você escreva o código uma única vez e o aplique em todos os lugares.
1. Você aprenderá
- Geração e validação de JWT
- Token de acesso + token de atualização (token duplo)
- RBAC (Controle de Acesso Baseado em Funções)
- Limitação de tráfego por balde de tokens
- Recuperação / Registro / Middleware CORS
- Pipelines de middleware em cascata
2. A história real de um engenheiro de backend
(1) Problema: verificar manualmente o token em cada roteador; esqueci de fazer isso três vezes.
Charlie faz parte da equipe do API Gateway e é responsável pela autenticação de todos os endpoints:
“O chefe exigiu que todas as APIs validassem os tokens JWT. Copiei e colei 15 linhas de código de validação de tokens em cada handler. No segundo dia após a implantação, esqueci de adicionar a autenticação ao
/admin/users— qualquer pessoa podia excluir usuários diretamente. O diretor de tecnologia disse: ‘A auditoria de segurança identificou uma vulnerabilidade grave.’”
// Bad code: manually check in every handler
func deleteUser(w http.ResponseWriter, r *http.Request) {
// Forgot to add Token verification! Serious security vulnerability
userID := r.PathValue("id")
deleteUserFromDB(userID)
}
func updateOrder(w http.ResponseWriter, r *http.Request) {
token := r.Header.Get("Authorization")
// Copy 15 lines of verification code each time
if !validateToken(token) {
http.Error(w, "unauthorized", 401)
return
}
// Business logic...
}
(2) Solução Go: Middleware de autenticação
// Good code: auth middleware, implement once, apply everywhere
func AuthMiddleware(jwtSecret string) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
token := extractToken(r)
claims, err := validateJWT(token, jwtSecret)
if err != nil {
writeError(w, http.StatusUnauthorized, "invalid token")
return
}
// Inject user info into Context
ctx := context.WithValue(r.Context(), "user", claims)
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// Registration only needs one Middleware
mux.Handle("POST /api/orders", AuthMiddleware(secret)(orderHandler))
(3) Vantagens: Método manual x middleware
| Dimensão | Verificação manual | Padrão de middleware |
|---|---|---|
| Risco de omissão | Existe o risco de esquecer de adicionar cada nova rota | Zero |
| Duplicação de código | 15 linhas por manipulador | 0 linhas (os manipuladores se concentram exclusivamente na lógica de negócios) |
| Modificar lógica | Modificar 20 manipuladores | Modificar 1 middleware |
| Testes unitários | Testar a autenticação para cada manipulador | Testar o middleware apenas uma vez |
3. Autenticação JWT
(1) ▶ Exemplo: Geração e validação de JWT
⚙️ Pré-requisito: Em ambiente de produção, use
go get github.com/golang-jwt/jwt/v5. O código abaixo é uma implementação manual destinada exclusivamente a fins educacionais.
package main
import (
"crypto/hmac"
"crypto/sha256"
"encoding/base64"
"encoding/json"
"fmt"
"strings"
"time"
)
// ---------- JWT manual impl (no third-party dependency) ----------
type JWTClaims struct {
UserID int `json:"user_id"`
Role string `json:"role"`
Permissions []string `json:"permissions"`
ExpiresAt int64 `json:"exp"`
}
type JWTHeader struct {
Alg string `json:"alg"`
Typ string `json:"typ"`
}
func base64Encode(data []byte) string {
return strings.TrimRight(base64.URLEncoding.EncodeToString(data), "=")
}
func base64Decode(s string) ([]byte, error) {
// Pad to proper length
switch len(s) % 4 {
case 2:
s += "=="
case 3:
s += "="
}
return base64.URLEncoding.DecodeString(s)
}
func createJWT(claims JWTClaims, secret string) (string, error) {
header := JWTHeader{Alg: "HS256", Typ: "JWT"}
headerJSON, _ := json.Marshal(header)
claimsJSON, _ := json.Marshal(claims)
headerEnc := base64Encode(headerJSON)
claimsEnc := base64Encode(claimsJSON)
// Sign
message := headerEnc + "." + claimsEnc
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(message))
signature := base64Encode(mac.Sum(nil))
return message + "." + signature, nil
}
func validateJWT(token string, secret string) (*JWTClaims, error) {
parts := strings.Split(token, ".")
if len(parts) != 3 {
return nil, fmt.Errorf("invalid token format")
}
// Verify signature
message := parts[0] + "." + parts[1]
mac := hmac.New(sha256.New, []byte(secret))
mac.Write([]byte(message))
expectedSig := base64Encode(mac.Sum(nil))
if !hmac.Equal([]byte(parts[2]), []byte(expectedSig)) {
return nil, fmt.Errorf("invalid signature")
}
// Parse claims
claimsJSON, err := base64Decode(parts[1])
if err != nil {
return nil, err
}
var claims JWTClaims
if err := json.Unmarshal(claimsJSON, &claims); err != nil {
return nil, err
}
// Check expiration
if time.Now().Unix() > claims.ExpiresAt {
return nil, fmt.Errorf("token expired")
}
return &claims, nil
}
func main() {
secret := "my-secret-key"
// Generate Token
claims := JWTClaims{
UserID: 1,
Role: "admin",
ExpiresAt: time.Now().Add(1 * time.Hour).Unix(),
}
token, _ := createJWT(claims, secret)
fmt.Printf("JWT: %s\n", token)
// Validate Token
validated, err := validateJWT(token, secret)
if err != nil {
fmt.Printf("Validation failed: %v\n", err)
} else {
fmt.Printf("Validation succeeded: user=%d, role=%s\n", validated.UserID, validated.Role)
}
}
github.com/golang-jwt/jwt/v5) em vez de implementá-la manualmente. O código acima tem como único objetivo ilustrar como os JWTs funcionam. Bibliotecas de terceiros lidam com mais casos especiais (como tipos de token, rotação de chaves e verificação de reivindicações padrão).
4. Token de acesso + token de atualização
(1) ▶ Exemplo: Autenticação com dois tokens
package main
import (
"crypto/rand"
"encoding/hex"
"encoding/json"
"fmt"
"net/http"
"sync"
"time"
)
// ---------- Token Service ----------
type TokenService struct {
secret string
refreshTTL time.Duration
// Store refresh tokens (use Redis in production)
refreshTokens map[string]int // token → userID
mu sync.RWMutex
}
func NewTokenService(secret string) *TokenService {
return &TokenService{
secret: secret,
refreshTTL: 7 * 24 * time.Hour,
refreshTokens: make(map[string]int),
}
}
func (s *TokenService) GenerateTokens(userID int, role string) (accessToken, refreshToken string, err error) {
// Access Token (expires in 15 minutes)
accessClaims := JWTClaims{
UserID: userID,
Role: role,
ExpiresAt: time.Now().Add(15 * time.Minute).Unix(),
}
accessToken, err = createJWT(accessClaims, s.secret)
if err != nil {
return "", "", err
}
// Refresh Token (random string, expires in 7 days)
bytes := make([]byte, 32)
rand.Read(bytes)
refreshToken = hex.EncodeToString(bytes)
s.mu.Lock()
s.refreshTokens[refreshToken] = userID
s.mu.Unlock()
return accessToken, refreshToken, nil
}
func (s *TokenService) RefreshAccessToken(refreshToken string) (string, error) {
s.mu.RLock()
userID, exists := s.refreshTokens[refreshToken]
s.mu.RUnlock()
if !exists {
return "", fmt.Errorf("invalid refresh token")
}
// Generate new Access Token
claims := JWTClaims{
UserID: userID,
Role: "user",
ExpiresAt: time.Now().Add(15 * time.Minute).Unix(),
}
return createJWT(claims, s.secret)
}
func (s *TokenService) RevokeRefreshToken(refreshToken string) {
s.mu.Lock()
delete(s.refreshTokens, refreshToken)
s.mu.Unlock()
}
// ---------- Auth Handler ----------
type AuthHandler struct {
tokenSvc *TokenService
}
type loginRequest struct {
Username string `json:"username"`
Password string `json:"password"`
}
type tokenResponse struct {
AccessToken string `json:"access_token"`
RefreshToken string `json:"refresh_token"`
TokenType string `json:"token_type"`
ExpiresIn int64 `json:"expires_in"`
}
func (h *AuthHandler) Login(w http.ResponseWriter, r *http.Request) {
var req loginRequest
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
return
}
// Verify username and password (use bcrypt in production)
if req.Username != "admin" || req.Password != "password" {
writeJSON(w, http.StatusUnauthorized, map[string]string{"error": "invalid credentials"})
return
}
accessToken, refreshToken, err := h.tokenSvc.GenerateTokens(1, "admin")
if err != nil {
writeJSON(w, http.StatusInternalServerError, map[string]string{"error": "token generation failed"})
return
}
writeJSON(w, http.StatusOK, tokenResponse{
AccessToken: accessToken,
RefreshToken: refreshToken,
TokenType: "Bearer",
ExpiresIn: 900, // 15 minutes
})
}
func (h *AuthHandler) Refresh(w http.ResponseWriter, r *http.Request) {
var req struct {
RefreshToken string `json:"refresh_token"`
}
if err := json.NewDecoder(r.Body).Decode(&req); err != nil {
writeJSON(w, http.StatusBadRequest, map[string]string{"error": "invalid JSON"})
return
}
accessToken, err := h.tokenSvc.RefreshAccessToken(req.RefreshToken)
if err != nil {
writeJSON(w, http.StatusUnauthorized, map[string]string{"error": "invalid refresh token"})
return
}
writeJSON(w, http.StatusOK, map[string]string{"access_token": accessToken})
}
func main() {
tokenSvc := NewTokenService("my-secret-key")
authHandler := &AuthHandler{tokenSvc: tokenSvc}
mux := http.NewServeMux()
mux.HandleFunc("POST /login", authHandler.Login)
mux.HandleFunc("POST /refresh", authHandler.Refresh)
fmt.Println("Auth service listening on :8080")
http.ListenAndServe(":8080", mux)
}
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
sequenceDiagram
participant Client
participant API as API Gateway
participant Auth as Auth Service
Client->>API: POST /login (username, password)
API->>Auth: Verify credentials
Auth-->>API: access_token (15min) + refresh_token (7d)
API-->>Client: Return dual tokens
Client->>API: GET /orders (Bearer access_token)
API->>API: Validate access_token
API-->>Client: 200 OK
Client->>API: GET /orders (access_token expired)
API-->>Client: 401 Unauthorized
Client->>API: POST /refresh (refresh_token)
API->>Auth: Validate refresh_token
Auth-->>API: New access_token
API-->>Client: Return new access_token
5. Middleware de permissões RBAC
(1) ▶ Exemplo: Implementação do RBAC
package main
import (
"context"
"encoding/json"
"net/http"
)
type UserRole string
const (
RoleAdmin UserRole = "admin"
RoleUser UserRole = "user"
RoleGuest UserRole = "guest"
)
// Permission definitions
var rolePermissions = map[UserRole][]string{
RoleAdmin: {"read:users", "write:users", "Excluir:users", "read:orders", "write:orders"},
RoleUser: {"read:orders", "write:orders"},
RoleGuest: {"read:products"},
}
type Claims struct {
UserID int
Role UserRole
}
// Get claims from Context
func GetClaims(r *http.Request) *Claims {
claims, _ := r.Context().Value("claims").(*Claims)
return claims
}
// RBAC middleware
func RequirePermission(permission string) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
claims := GetClaims(r)
if claims == nil {
writeError(w, http.StatusUnauthorized, "not authenticated")
return
}
permissions, exists := rolePermissions[claims.Role]
if !exists {
writeError(w, http.StatusForbidden, "no permissions defined for role")
return
}
// Check permission
hasPermission := false
for _, p := range permissions {
if p == permission {
hasPermission = true
break
}
}
if !hasPermission {
writeError(w, http.StatusForbidden, "insufficient permissions")
return
}
next.ServeHTTP(w, r)
})
}
}
// ---------- Route registration ----------
func setupRoutes() http.Handler {
mux := http.NewServeMux()
// Public endpoints
mux.HandleFunc("POST /login", loginHandler)
// Authenticated endpoints
mux.Handle("GET /api/orders", RequirePermission("read:orders")(authMiddleware(http.HandlerFunc(listOrders))))
mux.Handle("POST /api/orders", RequirePermission("write:orders")(authMiddleware(http.HandlerFunc(createOrder))))
mux.Handle("DELETE /api/users/{id}", RequirePermission("Excluir:users")(authMiddleware(http.HandlerFunc(deleteUser))))
return mux
}
(2) Pipeline de middleware
Request → Auth Middleware → RBAC Middleware → Handler
| |
Verify JWT Token Check Role permissions
Inject Claims User has permission?
| Nível | Middleware | Responsabilidades |
|---|---|---|
| 1 | Recuperação | Capturar panic, retornar 500 |
| 2 | Registro | Duração da solicitação de log |
| 3 | CORS | Como lidar com solicitações entre origens |
| 4 | Autenticação | Verificar JWT, inserir informações do usuário |
| 5 | RBAC | Verificar permissões da função |
| 6 | Limite de taxa | Limitação por balde de tokens |
| 7 | Handler | Lógica de negócios |
6. Limitação de tráfego por balde de tokens
(1) ▶ Exemplo: Implementação do modelo de balde de tokens
package main
import (
"net/http"
"sync"
"time"
)
type TokenBucket struct {
mu sync.Mutex
tokens float64
maxTokens float64
refillRate float64
lastRefill time.Time
}
func NewTokenBucket(rate float64, burst int) *TokenBucket {
return &TokenBucket{
tokens: float64(burst),
maxTokens: float64(burst),
refillRate: rate,
lastRefill: time.Now(),
}
}
func (tb *TokenBucket) Allow() bool {
tb.mu.Lock()
defer tb.mu.Unlock()
// Refill tokens
now := time.Now()
elapsed := now.Sub(tb.lastRefill).Seconds()
tb.tokens = min(tb.tokens+elapsed*tb.refillRate, tb.maxTokens)
tb.lastRefill = now
// Take a token
if tb.tokens >= 1 {
tb.tokens--
return true
}
return false
}
func min(a, b float64) float64 {
if a < b {
return a
}
return b
}
// IP rate limiter
type IPRateLimiter struct {
mu sync.RWMutex
buckets map[string]*TokenBucket
rate float64
burst int
}
func NewIPRateLimiter(rate float64, burst int) *IPRateLimiter {
return &IPRateLimiter{
buckets: make(map[string]*TokenBucket),
rate: rate,
burst: burst,
}
}
func (rl *IPRateLimiter) GetBucket(ip string) *TokenBucket {
rl.mu.Lock()
defer rl.mu.Unlock()
bucket, exists := rl.buckets[ip]
if !exists {
bucket = NewTokenBucket(rl.rate, rl.burst)
rl.buckets[ip] = bucket
}
return bucket
}
// RateLimiterMiddleware
func RateLimiterMiddleware(rate float64, burst int) Middleware {
limiter := NewIPRateLimiter(rate, burst)
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
bucket := limiter.GetBucket(ip)
if !bucket.Allow() {
w.Header().Set("Retry-After", "1")
writeError(w, http.StatusTooManyRequests, "rate limit exceeded")
return
}
next.ServeHTTP(w, r)
})
}
}
7. Exemplo completo: Pipeline de middleware do API Gateway
(1) ▶ Exemplo: Pipeline completo
// api_gateway.go
package main
import (
"context"
"encoding/json"
"log"
"net/http"
"os"
"os/signal"
"strings"
"syscall"
"time"
)
// ---------- Type definitions ----------
type Middleware func(http.Handler) http.Handler
type Claims struct {
UserID int
Role string
}
// ---------- Middleware ----------
// Recovery
func Recovery(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
defer func() {
if err := recover(); err != nil {
log.Printf("[PANIC] %v", err)
writeError(w, http.StatusInternalServerError, "internal error")
}
}()
next.ServeHTTP(w, r)
})
}
// Logging
func Logging(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
start := time.Now()
log.Printf("[%s] %s %s", r.Method, r.URL.Path, r.RemoteAddr)
next.ServeHTTP(w, r)
log.Printf("[%s] %s → %v", r.Method, r.URL.Path, time.Since(start))
})
}
// CORS
func CORS(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
w.Header().Set("Access-Control-Allow-Origin", "*")
w.Header().Set("Access-Control-Allow-Methods", "GET, POST, PUT, DELETE, OPTIONS")
w.Header().Set("Access-Control-Allow-Headers", "Content-Type, Authorization")
if r.Method == http.MethodOptions {
w.WriteHeader(http.StatusNoContent)
return
}
next.ServeHTTP(w, r)
})
}
// Auth (JWT authentication)
func Auth(secret string) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
authHeader := r.Header.Get("Authorization")
if !strings.HasPrefix(authHeader, "Bearer ") {
writeError(w, http.StatusUnauthorized, "missing token")
return
}
token := authHeader[7:]
claims, err := validateJWT(token, secret)
if err != nil {
writeError(w, http.StatusUnauthorized, err.Error())
return
}
ctx := context.WithValue(r.Context(), "claims", &Claims{
UserID: claims.UserID,
Role: claims.Role,
})
next.ServeHTTP(w, r.WithContext(ctx))
})
}
}
// RBAC
func RequireRole(roles ...string) Middleware {
return func(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
claims, ok := r.Context().Value("claims").(*Claims)
if !ok {
writeError(w, http.StatusUnauthorized, "not authenticated")
return
}
for _, role := range roles {
if claims.Role == role {
next.ServeHTTP(w, r)
return
}
}
writeError(w, http.StatusForbidden, "insufficient permissions")
})
}
}
// Rate Limiter
var rateLimiter = NewIPRateLimiter(10, 20) // 10 req/s, burst 20
func RateLimit(next http.Handler) http.Handler {
return http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
ip := r.RemoteAddr
bucket := rateLimiter.GetBucket(ip)
if !bucket.Allow() {
writeError(w, http.StatusTooManyRequests, "rate limit exceeded")
return
}
next.ServeHTTP(w, r)
})
}
// ---------- Chain ----------
func Chain(h http.Handler, mws ...Middleware) http.Handler {
for i := len(mws) - 1; i >= 0; i-- {
h = mws[i](h)
}
return h
}
// ---------- Handlers ----------
type OrderHandler struct{}
func (h *OrderHandler) ListOrders(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"orders": "list"})
}
func (h *OrderHandler) CreateOrder(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusCreated, map[string]string{"Ordem": "created"})
}
type AdminHandler struct{}
func (h *AdminHandler) DeleteUser(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"deleted": "user"})
}
// ---------- Utility functions ----------
func writeJSON(w http.ResponseWriter, status int, data interface{}) {
w.Header().Set("Content-Type", "application/json")
w.WriteHeader(status)
json.NewEncoder(w).Encode(data)
}
func writeError(w http.ResponseWriter, status int, msg string) {
writeJSON(w, status, map[string]string{"error": msg})
}
// ---------- Main ----------
func main() {
jwtSecret := "super-secret-key"
orders := &OrderHandler{}
mux := http.NewServeMux()
// Public endpoint
mux.HandleFunc("POST /login", func(w http.ResponseWriter, r *http.Request) {
writeJSON(w, http.StatusOK, map[string]string{"token": "login-token"})
})
// Authenticated + rate-limited endpoints
mux.Handle("GET /api/orders", Chain(
http.HandlerFunc(orders.ListOrders),
Auth(jwtSecret),
RateLimit,
))
mux.Handle("POST /api/orders", Chain(
http.HandlerFunc(orders.CreateOrder),
Auth(jwtSecret),
RateLimit,
))
// Admin endpoints (Auth + RBAC + RateLimit)
mux.Handle("DELETE /api/users/{id}", Chain(
http.HandlerFunc((&AdminHandler{}).DeleteUser),
Auth(jwtSecret),
RequireRole("admin"),
RateLimit,
))
// Global middleware (Recovery → Logging → CORS → routes)
app := Chain(mux, Recovery, Logging, CORS)
server := &http.Server{Addr: ":8080", Handler: app}
go func() {
sigCh := make(chan os.Signal, 1)
signal.Notify(sigCh, syscall.SIGINT, syscall.SIGTERM)
<-sigCh
log.Println("Shutting down...")
ctx, cancel := context.WithTimeout(context.Background(), 10*time.Second)
defer cancel()
server.Shutdown(ctx)
}()
log.Println("API Gateway listening on :8080")
if err := server.ListenAndServe(); err != http.ErrServerClosed {
log.Fatal(err)
}
}
❓ Perguntas Frequentes
P: Como o JWT é implementado? R: Um JWT é composto por três partes: cabeçalho (algoritmo + tipo), carga útil (reivindicações) e assinatura. O Go recomenda o uso do
github.com/golang-jwt/jwt/v5. Os tokens de acesso têm validade curta (15 minutos), enquanto os tokens de atualização têm validade longa (7 dias) e são armazenados no servidor.
P: Qual é a diferença entre um token de acesso e um token de atualização? R: Um token de acesso é usado para autenticação na API; ele é válido por um curto período (15 minutos) e contém informações do usuário e permissões. Um token de atualização é usado para obter um novo token de acesso; ele é válido por um longo período (7 dias) e fica armazenado no servidor. Quando o token de acesso expira, o cliente usa o token de atualização para obter automaticamente um novo token de acesso, sem que o usuário precise fazer login novamente.
P: Como o RBAC é implementado? R: O RBAC (Controle de Acesso Baseado em Funções) atribui um conjunto de permissões a cada função, e o middleware verifica se a função do usuário atual possui as permissões necessárias para a solicitação. Implementação:
rolePermissions[role] = []permission+ o middleware verificapermission in rolePermissions[claims.Role].
P: Qual algoritmo de limitação de taxa devo escolher? R: O token bucket é o mais utilizado — ele permite picos de tráfego e possibilita o controle da taxa média. Implementação: reabasteça o bucket com tokens de taxa por segundo, estabelecendo um limite para picos de tráfego. Cada solicitação consome um token; se não houver tokens suficientes, é retornado um erro 429. Adequado para limitação de taxa de API.
P: Como posso evitar que o middleware de recuperação suprime mensagens de pânico? R: Registre o rastreamento completo da pilha no processo de recuperação e, em seguida, retorne-o usando um tipo de erro personalizado.
debug.Stack()imprime o rastreamento da pilha. Use o nível de log ERROR. Em produção, não retorne o rastreamento da pilha ao cliente — registre-o apenas no servidor.
P: Qual é a ordem de execução do pipeline de middleware? R: O modelo em camadas.
Chain(h, A, B, C)→ A solicitação passa por A → B → C → Handler → C → B → A. Ordem de registro = da camada mais externa para a camada mais interna. A recuperação ocorre na camada mais externa (captura exceções de pânico lançadas por qualquer camada), e o Handler está na camada mais interna (lógica de negócios).
P: Como um JWT é revogado? R: Um JWT não mantém estado — uma vez emitido, não pode ser revogado até que expire. Solução: (1) Token de curto prazo + token de atualização (o token de atualização pode ser revogado); (2) Lista negra (armazenar IDs de JWTs revogados no Redis); (3) Número de versão (incrementar o número de versão quando um usuário alterar sua senha; os tokens antigos se tornam inválidos).
📖 Resumo
- JWT: Cabeçalho + Carga + Assinatura,
golang-jwt/jwt/v5 - Dois tokens: Acesso (15 min) + Atualização (7 dias)
- Middleware de autenticação: verifica o token e insere as reivindicações no contexto
- RBAC: mapeamento entre funções e permissões; o middleware verifica as permissões
- Limitação por “Token Bucket”: permite picos de tráfego e controla o fluxo médio
- Middleware de recuperação: captura um erro grave e retorna um código 500
- Ordem do middleware: Recuperação → Registro em log → CORS → Autenticação → RBAC → Limite de taxa → Manipulador
📝 Exercícios
-
Básico (Dificuldade ⭐): Implemente um middleware de autenticação simples. Crie um endpoint
/api/protectedque exija que o cabeçalho da solicitação incluaAuthorization: Bearer token123. Se o token for válido, retorne{"message": "access granted"}; caso contrário, retorne um erro 401. -
Avançado (Dificuldade ⭐⭐): Implemente um sistema completo de autenticação JWT. Requisitos: (1)
POST /registerpara cadastro (senha criptografada com bcrypt); (2)POST /loginpara login (retorna access_token + refresh_token); (3) Um middleware de autenticação que valide o access_token para todos os endpoints/api/*; (4)POST /refreshpara trocar orefresh_tokenpor um novoaccess_token; (5)POST /logoutpara revogar orefresh_token. -
Desafio (Dificuldade ⭐⭐⭐): Implemente uma API de gerenciamento de blog com RBAC e limitação de taxa. Requisitos: (1) Três funções: administrador, editor e leitor; (2) administrador: permissões totais; (3) editor: criar, editar e excluir suas próprias postagens; (4) leitor: acesso somente para leitura; (5) Cada função tem limites de taxa diferentes; (6) Todos os endpoints devem passar pelo seguinte pipeline de middleware: Recuperação → Registro → Autenticação → RBAC → Limite de Taxa → Manipulador; (7) Use
-racepara verificar a segurança de concorrência.