Blog EspecializaTi
Carlos Ferreira Por: Carlos Ferreira Comentar

Middleware no Laravel (Filtros)

Middleware é um poderoso mecanismo do laravel que permite filtrar requisições http em sua aplicação.

O laravel já possui alguns filtros embutido, como filtros de autenticação, filtro para usuários não autenticados, filtro para API, filtro de CORS para headers, filtro de CSRF para proteção contra este ataque em requisições http POST, PUT, PATH e DELETE.

E também é possível criar middlewares (filtros) personalizados no laravel para validar regras especificas de sua aplicação. É possível validar qualquer coisa com middlewares, como por exemplo se o usuário está ativo (neste caso pode restringir o acesso a apena usuários ativos), pode validar se o usuário concordou com os termos de uso, pode validar se o usuário tem permissão para fazer algo, e etc.

Os middlewares personalizados no laravel ficam /app/Http/Middleware/ e o arquivo de definição dos middlewares é /app/Http/Kernel.php

 

Criando novos middlewares:

Para criar um novo middleware no laravel basta aproveitar os recursos do artisan e criar uma nova classe de filtro através do comando:
php artisan make:middleware NomeDoMiddleware

Vamos criar um exemplo prático. Vamos criar um filtro para verificar se o e-mail do usuário logado é gmail.com, neste exemplo vamos permitir o acesso a determinadas partes da nossa aplicação a apenas usuários cujo o e-mail seja Gmail.

Primeiro passo, criar o middleware (Acesse o terminal e rode o comando para criar a classe de Middleware):

php artisan make:middleware CheckMailEqualsGmail

Observe que o nome do Middleware ficou bem claro com a responsabilidade do mesmo (verificar se o e-mail é igual ao gmail), é importante seguir essa regra para saber exatamente a responsabilidade de cada item na aplicação.

Ao rodar o comando vai criar a classe em /app/Http/Middleware/CheckMailEqualsGmail.php

Ao abrir a classe ela deve ter essa estrutura:

<?php

namespace App\Http\Middleware;

use Closure;

class CheckMailEqualsGmail
{
    /**
     * Handle an incoming request.
     *
     * @param  \Illuminate\Http\Request  $request
     * @param  \Closure  $next
     * @return mixed
     */
    public function handle($request, Closure $next)
    {
        return $next($request);
    }
}

Dentro do método handle() que deve fazer a verificação, ou seja, neste método que você faz o if para verificar se o usuário tem pode continuar ou não;

O primeiro parâmetro $request tem um objeto da Facade Request (Aquela mesma classe utilizada para recuperar dados do formulário, ou seja, recuperar dados de requisição http). O segundo parâmetro $next é um objeto de Closure que tem a requisição em si, ou seja, tem as propriedades da requisição para continuar ou não a navegação.

Ao deixar return $next($request); isso dá continuidade e permite o acesso. Se não quer permitir o acesso precisa fazer um return antes desta linha.

 

Vamos a verificação?
Neste exemplo vamos verificar duas coisas, a primeira se o usuário está logado (embora o laravel possua filtros para isso “auth“), é importante verificar isso porque se não colocar esse filtro de “auth” e deixar apenas o nosso e o usuário tentar acessar sem estar logado vai gerar erro.
E o segundo filtro é o nosso objetivo, verificar se o usuário tem e-mail do Gmail.

Veja como fica o método handle():

public function handle($request, Closure $next)
{
    // Verifica se está logado, se não tiver redireciona
    if ( !auth()->check() )
        return redirect()->route('login');

    /*
    * Verifica se o e-mail é Gmail
    */
    // Recupera o e-mail do usuário logado
    $email = auth()->user()->email;

    //Recupera o servidor do e-mail
    $dataMail = explode('@', $email);
    $serverMail = $dataMail[1];

    // Verifica se é gmail.com, caso não se redireciona para a Home Page
    if ( $serverMail != 'gmail.com' )
        return redirect('/');


    // Permite que continue (Caso não entre em nenhum dos if acima)...
    return $next($request);
}

Agora precisamos registrar o middleware que criamos, acesse o arquivo /app/Http/Kernel.php e no array $routeMiddleware adiciona mais um elemento, com o nome do middleware e a classe, veja:

/**
 * The application's route middleware.
 *
 * These middleware may be assigned to groups or used individually.
 *
 * @var array
 */
protected $routeMiddleware = [
    'auth' => \Illuminate\Auth\Middleware\Authenticate::class,
    'auth.basic' => \Illuminate\Auth\Middleware\AuthenticateWithBasicAuth::class,
    'bindings' => \Illuminate\Routing\Middleware\SubstituteBindings::class,
    'can' => \Illuminate\Auth\Middleware\Authorize::class,
    'guest' => \App\Http\Middleware\RedirectIfAuthenticated::class,
    'throttle' => \Illuminate\Routing\Middleware\ThrottleRequests::class,
    'check.gmail' => \App\Http\Middleware\CheckMailEqualsGmail::class,
];

Neste exemplo definimos que o nome do nosso middleware (filtro) é “check.gmail“.

 

Como utilizar?
É possível utilizar este middleware nas rotas, assim:

$this->get('url-aqui', '[email protected]')->middleware(['check.gmail']);

Em grupo de rotas, destas duas maneiras:

Route::middleware(['auth', 'check.gmail'])->group(function () {
    // Precisa estar autenticado e o e-mail ser gmail para conseguir acessar 🙂

    Route::get('/', '[email protected]');

    Route::get('outra-rota', '[email protected]');
});

Route::group(['middleware' => ['auth', 'check.gmail']], function() {
    // Precisa estar autenticado e o e-mail ser gmail para conseguir acessar 🙂

    Route::get('/', '[email protected]');

    Route::get('outra-rota', '[email protected]');
});

Ainda nas rotas é possível verificar assim (embora eu não aprove este método, porque precisa dá use em classe dentro do arquivo de rotas):

use App\Http\Middleware\CheckMailEqualsGmail;
$this->get('url-aqui', '[email protected]')->middleware(CheckMailEqualsGmail::class);

 

Registrar Middleware (filtro):

No último exemplo registramos nosso novo middleware no arquivo /app/Http/Kernel.php no array $routeMiddleware.

No array $routeMiddleware deve ficar os middlewares com seu respectivo nome.

No array $middleware deve ficar os middleware globais, ou seja, os filtros para toda a aplicação, o que colocar neste array já funciona automaticamente em toda a APP.
Já existe alguns middlweare globais registrado no laravel:

  • CheckForMaintenanceMode: Verifica se a aplicação está em modo de manutenção
  • ValidatePostSize: Valida o tamanho do POST enviado, valida se a requisição não ultrapassa a tamanho máximo que as configurações do servidor permite, evita erros.
  • TrimStrings: Retira os espaços (Utiliza a função trim())
  • ConvertEmptyStringsToNull: Apenas converte valores vazios ” para NULL

 

O array $middlewareGroups é possível criar um middleware novo com diversos filtros incluído, podemos refazer nosso exemplo para que o mesmo middleware “check.gmail” já verifique se o usuário está logado, veja:

/**
 * The application's route middleware groups.
 *
 * @var array
 */
protected $middlewareGroups = [
    'web' => [
        \App\Http\Middleware\EncryptCookies::class,
        \Illuminate\Cookie\Middleware\AddQueuedCookiesToResponse::class,
        \Illuminate\Session\Middleware\StartSession::class,
        // \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\VerifyCsrfToken::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
    ],

    'api' => [
        'throttle:60,1',
        'bindings',
    ],

    'check.gmail' => [
        \Illuminate\Auth\Middleware\Authenticate::class,
        \App\Http\Middleware\CheckMailEqualsGmail::class,
    ],
];

Ao deixar o middleware “check.gmail” no array $middlewareGroups agora verifica tanto se está autenticado e verifica também se o e-mail é Gmail.

Pode até retirar do método handle() na classe de middleware CheckMailEqualsGmail a verificação se o usuário está autenticado:
// Não precisa mais disso
if ( !auth()->check() )
return redirect()->route(‘login’);

 

Parâmetros Middleware:

É possível receber parâmetros em um middleware.

Para exemplificar vamos refazer o mesmo exemplo que verificar se o e-mail é gmail.com e permitir que seja informado o valor a ser verificado.

Primeiro passo, refatorar o método handle() para receber o novo parâmetro (lembrando que pode receber vários parâmetros, quantos for necessário):

public function handle($request, Closure $next, $serverMail = 'gmail.com')
{
    /*
    * Verifica se o e-mail é igual a valor informado, ou 'gmail.com'
    */
    // Recupera o e-mail do usuário logado
    $email = auth()->user()->email;

    // Recupera o servidor do e-mail
    $dataMail = explode('@', $email);
    $serverMailUser = $dataMail[1];

    // Verifica se é igual $serverMail, caso não se redireciona para a Home Page
    if ( $serverMailUser != $serverMail )
        return redirect('/');


    // Permite que continue (Caso não entre em nenhum dos if acima)...
    return $next($request);
}

Agora como o middleware não verifica apenas e-mail do gmail é interessante ir no arquivo /app/Http/Kernel.php e refatorar o nome deixando algo mais genérico, como por exemplo “check.email“, exemplo:

'check.email' => [
    \Illuminate\Auth\Middleware\Authenticate::class,
    \App\Http\Middleware\CheckMailEqualsGmail::class,
],

PS. Se quiser renomear a classe e o nome do arquivo de CheckMailEqualsGmail para algo mais genérico, como: CheckMailEquals

Agora para utilizar nosso filtro refatorado basta utilizar o middleware pelo seu nome “check.email” e passar o servidor de e-mail, se não informar nada por default será “gmail.com

 

Veja como utilizar:

$this->get('url-aqui', '[email protected]')->middleware('check.email:especializati.com.br');

 

 

Terminable Middleware:

Outro recurso com middleware é executar uma operação após o middleware.
O middleware ele é utilizado before (antes) de concluir a requisição.

Uma opção que pode ser interessante dependendo da aplicação é executar algo depois que concluir a verificação, para isso basta criar um método chamado terminate() no Middleware, veja um exemplo:

public function terminate($request, $response)
{
    \Log::info('terminate middleware', $request);
    \Log::info('terminate middleware', $response);
}

O parâmetro $request é um objeto da Facade Request e o $response é um objeto com os dados da reposta requisição.

 

 

Carlos Ferreira

Sobre o Autor:

Carlos Ferreira

Carlos Ferreira é Analista de Sistemas Experiente, Empreendedor, Fundador da empresa EspecializaTi. Certificações: Comptia Linux +, LPI, Novell Certification.

Todos os direitos reservados © 2021 - EspecializaTi. É proibida a reprodução total ou parcial deste conteúdo.