Laravel Middleware em profundidade: Autenticação, Rate Limiting e Middleware personalizado

Dominar o middleware do Laravel com exemplos práticos: guards de autenticação, limitação de taxa com throttle, criação de middleware personalizado, atributos PHP no Laravel 13 e padrões avançados para aplicações em produção.

Arquitetura de middleware do Laravel mostrando o pipeline de requisições com camadas de autenticação e limitação de taxa

O middleware do Laravel funciona como uma camada de filtragem entre as requisições HTTP recebidas e a lógica da aplicação. Cada requisição percorre um pipeline de classes middleware antes de chegar a um controller, e cada resposta viaja de volta pelo mesmo pipeline. Compreender esse mecanismo é fundamental para construir aplicações Laravel seguras e de alto desempenho.

Middleware em resumo

O middleware intercepta requisições HTTP antes que elas alcancem as rotas. O Laravel registra todos os middleware em bootstrap/app.php usando uma API fluente. Os middleware integrados gerenciam autenticação, proteção CSRF, gerenciamento de sessões e limitação de taxa nativamente.

Como funciona o pipeline de middleware no Laravel

O kernel HTTP do Laravel processa cada requisição através de uma pilha de middleware. Cada middleware recebe a requisição, executa sua lógica e então passa a requisição para a próxima camada via $next($request) ou interrompe o pipeline retornando uma resposta diretamente.

Essa arquitetura segue o padrão de projeto Chain of Responsibility. Um middleware pode atuar antes de a requisição alcançar o controller (por exemplo, verificações de autenticação), depois que a resposta é gerada (por exemplo, adicionando cabeçalhos), ou em ambos os momentos.

app/Http/Middleware/LogRequestTime.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Log;
use Symfony\Component\HttpFoundation\Response;

class LogRequestTime
{
    public function handle(Request $request, Closure $next): Response
    {
        $start = microtime(true);          // Capture start time

        $response = $next($request);       // Pass to next middleware

        $duration = microtime(true) - $start;
        Log::info('Request completed', [
            'url'      => $request->url(),
            'method'   => $request->method(),
            'duration' => round($duration * 1000, 2) . 'ms',
        ]);

        return $response;                  // Return response up the stack
    }
}

Esse middleware envolve a requisição: ele registra o tempo de início antes do processamento e registra a duração depois que a resposta retorna. Esse padrão antes/depois é central no funcionamento dos middleware.

Middleware de autenticação: protegendo rotas

O Laravel inclui o alias de middleware auth, mapeado para Illuminate\Auth\Middleware\Authenticate. Ao aplicá-lo a uma rota, apenas usuários autenticados conseguem acessá-la. Usuários não autenticados recebem uma resposta 401 (API) ou são redirecionados para a página de login (web).

routes/web.phpphp
use App\Http\Controllers\DashboardController;
use App\Http\Controllers\ProfileController;

// Single route protection
Route::get('/dashboard', [DashboardController::class, 'index'])
    ->middleware('auth');

// Group protection for multiple routes
Route::middleware('auth')->group(function () {
    Route::get('/profile', [ProfileController::class, 'show']);
    Route::put('/profile', [ProfileController::class, 'update']);
    Route::delete('/profile', [ProfileController::class, 'destroy']);
});

Autenticação com múltiplos guards

Aplicações com vários tipos de usuários (painel administrativo, área do cliente, API) se beneficiam da autenticação baseada em guards. O middleware auth aceita um parâmetro de guard para especificar qual driver de autenticação deve ser utilizado.

routes/api.phpphp
// API routes use the 'sanctum' guard
Route::middleware('auth:sanctum')->group(function () {
    Route::get('/user', fn (Request $request) => $request->user());
    Route::apiResource('/orders', OrderController::class);
});

// routes/web.php
// Admin routes use a custom 'admin' guard
Route::middleware('auth:admin')->prefix('admin')->group(function () {
    Route::get('/dashboard', [AdminController::class, 'index']);
    Route::get('/users', [AdminController::class, 'users']);
});

O parâmetro de guard após os dois pontos indica ao Laravel qual configuração de autenticação verificar. Essa abordagem mantém a lógica de autenticação organizada e separada entre as diferentes partes da aplicação.

Middleware Guest

O middleware guest é o inverso do auth, ele permite a passagem apenas de usuários não autenticados. Ao aplicá-lo às rotas de login e cadastro, impede-se que usuários já autenticados acessem essas páginas.

Limitação de taxa com o middleware Throttle

A limitação de taxa via middleware no Laravel protege as rotas contra abusos usando o middleware integrado throttle. Sua forma mais simples aceita dois parâmetros: o número máximo de requisições e a janela de tempo em minutos.

routes/api.phpphp
// Allow 60 requests per minute per user
Route::middleware('throttle:60,1')->group(function () {
    Route::get('/posts', [PostController::class, 'index']);
    Route::get('/posts/{post}', [PostController::class, 'show']);
});

// Stricter limit for write operations
Route::middleware(['auth:sanctum', 'throttle:10,1'])->group(function () {
    Route::post('/posts', [PostController::class, 'store']);
    Route::put('/posts/{post}', [PostController::class, 'update']);
});

Rate limiters nomeados para controle avançado

Definir rate limiters nomeados no AppServiceProvider oferece controle granular sobre os limites com base no contexto do usuário. Essa abordagem é mais flexível do que os parâmetros throttle inline. Consultar a documentação oficial de limitação de taxa para opções adicionais.

app/Providers/AppServiceProvider.phpphp
use Illuminate\Cache\RateLimiting\Limit;
use Illuminate\Support\Facades\RateLimiter;
use Illuminate\Http\Request;

public function boot(): void
{
    // API rate limiter with tiered access
    RateLimiter::for('api', function (Request $request) {
        $user = $request->user();

        if ($user?->hasSubscription('enterprise')) {
            return Limit::perMinute(500)->by($user->id);   // Enterprise: 500/min
        }

        if ($user) {
            return Limit::perMinute(100)->by($user->id);   // Authenticated: 100/min
        }

        return Limit::perMinute(20)->by($request->ip());   // Anonymous: 20/min
    });

    // Login limiter to prevent brute force
    RateLimiter::for('login', function (Request $request) {
        return Limit::perMinute(5)
            ->by($request->ip())                            // Key by IP address
            ->response(function () {                        // Custom exceeded response
                return response()->json([
                    'message' => 'Too many login attempts. Try again in a minute.',
                ], 429);
            });
    });
}

A aplicação de limiters nomeados às rotas utiliza a sintaxe throttle:name:

routes/api.phpphp
Route::middleware('throttle:api')->group(function () {
    Route::apiResource('/posts', PostController::class);
});

// routes/web.php
Route::middleware('throttle:login')
    ->post('/login', [AuthController::class, 'login']);

O rate limiter escalonado acima demonstra um padrão de produção: usuários enterprise obtêm limites mais altos, usuários autenticados recebem limites moderados, e requisições anônimas são restringidas de forma agressiva. O método by() determina a chave de limitação, usando o ID do usuário para usuários autenticados e o endereço IP como fallback.

Pronto para mandar bem nas entrevistas de Laravel?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Criando middleware personalizado do zero

A criação de middleware personalizado cobre cenários que os middleware integrados não tratam. O comando Artisan make:middleware gera uma nova classe com a estrutura correta.

bash
php artisan make:middleware EnsureUserHasRole

Middleware de controle de acesso baseado em papéis

Um padrão comum de middleware personalizado aplica autorização baseada em papéis no nível da rota, aceitando nomes de papéis como parâmetros.

app/Http/Middleware/EnsureUserHasRole.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class EnsureUserHasRole
{
    public function handle(Request $request, Closure $next, string ...$roles): Response
    {
        $user = $request->user();

        if (! $user || ! $user->hasAnyRole($roles)) {
            abort(403, 'Insufficient permissions.');
        }

        return $next($request);
    }
}

O parâmetro variádico ...$roles permite passar múltiplos papéis separados por vírgulas. O registro e a utilização ficam assim:

bootstrap/app.phpphp
->withMiddleware(function (Middleware $middleware) {
    $middleware->alias([
        'role' => \App\Http\Middleware\EnsureUserHasRole::class,
    ]);
})

// routes/web.php
Route::middleware('role:admin')->group(function () {
    Route::get('/admin', [AdminController::class, 'index']);
});

// Multiple roles: admin OR editor can access
Route::middleware('role:admin,editor')->group(function () {
    Route::resource('/articles', ArticleController::class);
});

Middleware de transformação de requisições

Um middleware pode modificar a requisição antes que ela alcance o controller. A seguir, um middleware para API JSON que impõe cabeçalhos de tipo de conteúdo e limpa as entradas do tipo string:

app/Http/Middleware/ApiRequestSanitizer.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Symfony\Component\HttpFoundation\Response;

class ApiRequestSanitizer
{
    public function handle(Request $request, Closure $next): Response
    {
        // Reject non-JSON requests on API routes
        if (! $request->expectsJson() && $request->isMethod('POST')) {
            return response()->json(
                ['error' => 'Content-Type must be application/json'],
                415
            );
        }

        // Trim all string inputs
        $input = $request->all();
        array_walk_recursive($input, function (&$value) {
            if (is_string($value)) {
                $value = trim($value);
            }
        });
        $request->merge($input);

        return $next($request);
    }
}

Esse middleware cuida de duas responsabilidades: valida o tipo de conteúdo para requisições POST e sanitiza todas as entradas de texto removendo espaços em branco desnecessários.

Registro de middleware em bootstrap/app.php

O Laravel centraliza todo o registro de middleware no arquivo bootstrap/app.php. Essa abordagem substituiu o antigo app/Http/Kernel.php que existia antes do Laravel 11. A mesma API fluente funciona no Laravel 12 e 13.

bootstrap/app.phpphp
use Illuminate\Foundation\Application;
use Illuminate\Foundation\Configuration\Middleware;

return Application::configure(basePath: dirname(__DIR__))
    ->withMiddleware(function (Middleware $middleware) {
        // Global middleware (runs on every request)
        $middleware->append(
            \App\Http\Middleware\LogRequestTime::class
        );

        // Add to the 'web' middleware group
        $middleware->web(append: [
            \App\Http\Middleware\TrackPageViews::class,
        ]);

        // Add to the 'api' middleware group
        $middleware->api(prepend: [
            \App\Http\Middleware\ApiRequestSanitizer::class,
        ]);

        // Register aliases for route-level use
        $middleware->alias([
            'role'       => \App\Http\Middleware\EnsureUserHasRole::class,
            'subscribed' => \App\Http\Middleware\EnsureUserIsSubscribed::class,
        ]);

        // Control execution order
        $middleware->priority([
            \Illuminate\Session\Middleware\StartSession::class,
            \Illuminate\Auth\Middleware\Authenticate::class,
            \App\Http\Middleware\EnsureUserHasRole::class,
        ]);
    })
    ->create();

O array priority é importante quando múltiplos middleware são atribuídos à mesma rota. O Laravel os ordena de acordo com essa lista, garantindo que a sessão seja iniciada antes da autenticação, e que a autenticação seja concluída antes das verificações de papel.

Ordem de execução dos middleware

Os middleware são executados na ordem de registro. Para middleware de rota, o array priority sobrescreve a ordem padrão. A autenticação deve ser sempre posicionada antes da autorização para evitar verificar papéis em requisições não autenticadas.

Atributos PHP para middleware no Laravel 13

O Laravel 13 introduziu o atributo PHP #[Middleware] para declarar middleware diretamente em classes e métodos de controller. Essa abordagem mantém a configuração do middleware junto ao código que ele protege, tornando as regras de autorização mais legíveis e fáceis de manter.

app/Http/Controllers/CommentController.phpphp
namespace App\Http\Controllers;

use App\Models\Comment;
use App\Models\Post;
use Illuminate\Routing\Attributes\Controllers\Authorize;
use Illuminate\Routing\Attributes\Controllers\Middleware;

#[Middleware('auth')]
class CommentController
{
    #[Middleware('subscribed')]
    #[Authorize('create', [Comment::class, 'post'])]
    public function store(Post $post)
    {
        // Only authenticated, subscribed users who can create comments reach here
    }

    public function index(Post $post)
    {
        // Still requires auth (from class-level attribute)
        return $post->comments;
    }
}

O atributo #[Middleware('auth')] no nível da classe se aplica a todos os métodos. Os atributos no nível dos métodos se acumulam: store() requer tanto auth quanto subscribed. O atributo #[Authorize] se integra ao sistema de policies do Laravel, verificando as permissões antes da execução do método.

Essa abordagem baseada em atributos é opcional. Os middleware definidos em arquivos de rotas e o registro em bootstrap/app.php continuam totalmente suportados. Equipes que preferem definições de rota explícitas podem continuar usando a API fluente; equipes que desejam controllers autodocumentados podem adotar os atributos.

Middleware terminável para tarefas pós-resposta

O middleware terminável executa lógica após a resposta ter sido enviada ao cliente. Isso é particularmente útil para tarefas de logging, analytics ou limpeza que não devem bloquear o usuário.

app/Http/Middleware/CollectAnalytics.phpphp
namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\DB;
use Symfony\Component\HttpFoundation\Response;

class CollectAnalytics
{
    public function handle(Request $request, Closure $next): Response
    {
        return $next($request);  // Pass through without delay
    }

    public function terminate(Request $request, Response $response): void
    {
        // Runs after response is sent to client
        DB::table('analytics')->insert([
            'path'        => $request->path(),
            'method'      => $request->method(),
            'status_code' => $response->getStatusCode(),
            'user_id'     => $request->user()?->id,
            'ip'          => $request->ip(),
            'created_at'  => now(),
        ]);
    }
}

O método terminate recebe tanto a requisição original quanto a resposta final. Recomenda-se registrar esse middleware como singleton no AppServiceProvider para garantir que a mesma instância trate tanto handle() quanto terminate().

Padrões de middleware para produção

Diversos padrões de middleware aparecem consistentemente em aplicações Laravel em produção.

Bypass do modo de manutenção, permitir que IPs internos acessem a aplicação durante a manutenção:

app/Http/Middleware/MaintenanceBypass.phpphp
class MaintenanceBypass
{
    private array $allowedIps = ['192.168.1.0/24', '10.0.0.1'];

    public function handle(Request $request, Closure $next): Response
    {
        if (app()->isDownForMaintenance()) {
            foreach ($this->allowedIps as $ip) {
                if ($request->ip() === $ip) {
                    return $next($request);
                }
            }
        }

        return $next($request);
    }
}

Cabeçalhos de segurança, adicionar HSTS, política de segurança de conteúdo e outros cabeçalhos a cada resposta:

app/Http/Middleware/SecurityHeaders.phpphp
class SecurityHeaders
{
    public function handle(Request $request, Closure $next): Response
    {
        $response = $next($request);

        $response->headers->set('X-Content-Type-Options', 'nosniff');
        $response->headers->set('X-Frame-Options', 'SAMEORIGIN');
        $response->headers->set('Referrer-Policy', 'strict-origin-when-cross-origin');
        $response->headers->set(
            'Strict-Transport-Security',
            'max-age=31536000; includeSubDomains'
        );

        return $response;
    }
}

Esses padrões ilustram as duas posições principais dos middleware: antes da requisição (o bypass de manutenção verifica o IP e potencialmente bloqueia o acesso) e depois da resposta (os cabeçalhos de segurança modificam a resposta de saída).

Pronto para mandar bem nas entrevistas de Laravel?

Pratique com nossos simuladores interativos, flashcards e testes tecnicos.

Fontes

Padrões de middleware Laravel para preparação de entrevistas

  • O middleware do Laravel opera como um pipeline: cada classe processa a requisição, atua sobre ela e a passa adiante ou interrompe o fluxo com uma resposta
  • O middleware auth protege rotas com autenticação baseada em guards, suportando múltiplos tipos de usuários via sintaxe auth:guard
  • A limitação de taxa através do middleware throttle e das definições nomeadas RateLimiter::for() permite controle de acesso escalonado com base no contexto do usuário
  • Os middleware personalizados tratam preocupações transversais como verificações de papel, sanitização de requisições e cabeçalhos de segurança sem sobrecarregar os controllers
  • Todo o registro de middleware acontece em bootstrap/app.php usando uma API fluente, com priority controlando a ordem de execução
  • O atributo #[Middleware] do Laravel 13 permite declarar middleware diretamente nos controllers, mantendo as regras de autorização junto aos handlers
  • O middleware terminável executa tarefas pós-resposta (analytics, logging) sem impactar a latência percebida pelo usuário
  • Os parâmetros de middleware via sintaxe :param mantêm as definições de rota expressivas e as classes middleware reutilizáveis em diferentes contextos

Comece a praticar!

Teste seus conhecimentos com nossos simuladores de entrevista e testes tecnicos.

Desafio do dia

Você saberia encontrar o bug em Laravel?

Um trecho real, um bug escondido, uma tentativa por dia. Sem conta para testar.

Anthony Fillion-Maillet

Escrito por

Anthony Fillion-Maillet

Fundador da SharpSkill

Desenvolvedor fullstack há mais de 10 anos. Dirige a SharpSkill e responde por tudo o que é publicado aqui.

Atualizado em 21 de setembro de 2026

Tags

#laravel
#middleware
#authentication
#rate-limiting
#php

Compartilhar

Artigos relacionados