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á


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.’”

GO
// 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

GO
// 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.

GO 📖 Somente leitura
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)
    }
}
85 linhas de lógica (limite de 40, somente leitura)
💡 Dica: Em um ambiente de produção, use uma biblioteca JWT madura (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

GO 📖 Somente leitura
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)
}
124 linhas de lógica (limite de 40, somente leitura)
100%
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

GO 📖 Somente leitura
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
}
61 linhas de lógica (limite de 40, somente leitura)

(2) Pipeline de middleware

TEXT 📖 Somente leitura
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

GO 📖 Somente leitura
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)
        })
    }
}
78 linhas de lógica (limite de 40, somente leitura)

7. Exemplo completo: Pipeline de middleware do API Gateway

(1) ▶ Exemplo: Pipeline completo

GO 📖 Somente leitura
// 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)
    }
}
164 linhas de lógica (limite de 40, somente leitura)
🔥 Erro comum: A ordem do middleware é fundamental. A recuperação deve ser a camada mais externa (para interceptar todos os erros graves). A autenticação (Auth) e o RBAC devem vir antes do RateLimit — a limitação de taxa deve se aplicar também a solicitações não autenticadas, mas usuários não autenticados não devem ter permissão para consumir tokens primeiro. Ordem geral: Recuperação → Registro em log → CORS → Autenticação → RBAC → RateLimit → Handler.


❓ 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 verifica permission 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


📝 Exercícios

  1. Básico (Dificuldade ⭐): Implemente um middleware de autenticação simples. Crie um endpoint /api/protected que exija que o cabeçalho da solicitação inclua Authorization: Bearer token123. Se o token for válido, retorne {"message": "access granted"}; caso contrário, retorne um erro 401.

  2. Avançado (Dificuldade ⭐⭐): Implemente um sistema completo de autenticação JWT. Requisitos: (1) POST /register para cadastro (senha criptografada com bcrypt); (2) POST /login para login (retorna access_token + refresh_token); (3) Um middleware de autenticação que valide o access_token para todos os endpoints /api/*; (4) POST /refresh para trocar o refresh_token por um novo access_token; (5) POST /logout para revogar o refresh_token.

  3. 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 -race para verificar a segurança de concorrência.

Web-Tutorial.com

Equipe Técnica Web-Tutorial

Uma plataforma de tutoriais mantida por diversos desenvolvedores. Cada tutorial é escrito e revisado por profissionais da área correspondente. Trabalhamos para manter nosso conteúdo preciso e confiável — se encontrar algum problema, avise-nos.

100%