Artigo 44 — Autenticação e Autorização no Laravel
Módulo 7 · Semana 44 · Nível: Intermediário–Avançado
Introdução
Autenticação responde "quem é você?" — verifica identidade. Autorização responde "o que você pode fazer?" — verifica permissões. Laravel oferece infraestrutura completa para ambas, com flexibilidade para ir do simples ao complexo conforme o sistema cresce.
Laravel Breeze — scaffolding de autenticação
Para a maioria dos projetos, o ponto de partida é o Laravel Breeze:
composer require laravel/breeze --dev
php artisan breeze:install blade # ou: react, vue, api
php artisan migrate
npm install && npm run dev
O Breeze instala: rotas de login/registro/logout/reset de senha, controllers, views Blade completas, e middleware de autenticação — tudo pronto para customizar.
Autenticação manual
Entender como funciona por baixo é fundamental:
<?php
declare(strict_types=1);
namespace App\Http\Controllers;
use Illuminate\Http\Request;
use Illuminate\Http\RedirectResponse;
use Illuminate\Support\Facades\Auth;
use Illuminate\Validation\ValidationException;
class LoginController extends Controller
{
public function store(Request $request): RedirectResponse
{
$credenciais = $request->validate([
'email' => ['required', 'email'],
'senha' => ['required'],
]);
// Auth::attempt verifica email + senha e cria a sessão
if (!Auth::attempt(
['email' => $credenciais['email'], 'password' => $credenciais['senha']],
$request->boolean('lembrar'), // "Lembrar de mim"
)) {
throw ValidationException::withMessages([
'email' => 'Email ou senha incorretos.',
]);
}
// Regenera session ID — previne session fixation
$request->session()->regenerate();
return redirect()->intended(route('dashboard'));
}
public function destroy(Request $request): RedirectResponse
{
Auth::logout();
$request->session()->invalidate();
$request->session()->regenerateToken();
return redirect()->route('login');
}
}
Middleware de autenticação
<?php
// routes/web.php
// Proteger rotas com middleware auth
Route::middleware('auth')->group(function () {
Route::get('/dashboard', [DashboardController::class, 'index'])->name('dashboard');
Route::resource('pedidos', PedidoController::class);
});
// Redirecionar usuários já autenticados
Route::middleware('guest')->group(function () {
Route::get('/login', [LoginController::class, 'create'])->name('login');
Route::post('/login', [LoginController::class, 'store']);
});
Autorização com Gates e Policies
Gates — regras simples de autorização definidas em closures:
<?php
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Gate;
public function boot(): void
{
Gate::define('editar-produto', function (User $usuario, Produto $produto) {
return $usuario->isAdmin() || $produto->criado_por === $usuario->id;
});
Gate::define('acessar-admin', function (User $usuario) {
return $usuario->role === 'admin';
});
}
// Uso no controller:
public function update(Request $request, Produto $produto): RedirectResponse
{
Gate::authorize('editar-produto', $produto); // lança 403 se não autorizado
$produto->update($request->validated());
return redirect()->route('produtos.show', $produto);
}
// Verificação sem lançar exceção:
if (Gate::allows('acessar-admin')) {
// mostra menu admin
}
if (Gate::denies('editar-produto', $produto)) {
abort(403);
}
Policies — autorização encapsulada por Model, para projetos maiores:
php artisan make:policy ProdutoPolicy --model=Produto
<?php
namespace App\Policies;
use App\Models\Produto;
use App\Models\User;
class ProdutoPolicy
{
// Antes de qualquer método — admin pode tudo
public function before(User $user): ?bool
{
if ($user->isAdmin()) return true;
return null; // null = continua verificando o método específico
}
public function viewAny(User $user): bool
{
return true; // qualquer usuário autenticado pode listar
}
public function view(User $user, Produto $produto): bool
{
return $produto->ativo || $user->isAdmin();
}
public function create(User $user): bool
{
return $user->hasPermission('criar-produto');
}
public function update(User $user, Produto $produto): bool
{
return $user->id === $produto->criado_por;
}
public function delete(User $user, Produto $produto): bool
{
return $user->id === $produto->criado_por && $produto->pedidos()->count() === 0;
}
}
// Registrar a policy (Laravel detecta automaticamente por convenção)
// app/Providers/AppServiceProvider.php
use Illuminate\Support\Facades\Gate;
Gate::policy(Produto::class, ProdutoPolicy::class);
// Uso no controller:
public function update(ProdutoRequest $request, Produto $produto): RedirectResponse
{
$this->authorize('update', $produto); // usa ProdutoPolicy::update()
$produto->update($request->validated());
return redirect()->route('produtos.show', $produto);
}
// No Blade:
@can('update', $produto)
<a href="{{ route('produtos.edit', $produto) }}">Editar</a>
@endcan
@cannot('delete', $produto)
<span class="desabilitado">Não pode deletar</span>
@endcannot
Roles e Permissions — sistema completo
Para sistemas maiores, o pacote spatie/laravel-permission é padrão do mercado:
composer require spatie/laravel-permission
php artisan vendor:publish --provider="Spatie\Permission\PermissionServiceProvider"
php artisan migrate
<?php
use Spatie\Permission\Models\Role;
use Spatie\Permission\Models\Permission;
// Setup de roles e permissions
$admin = Role::create(['name' => 'admin']);
$editor = Role::create(['name' => 'editor']);
$cliente = Role::create(['name' => 'cliente']);
Permission::create(['name' => 'criar produto']);
Permission::create(['name' => 'editar produto']);
Permission::create(['name' => 'deletar produto']);
Permission::create(['name' => 'ver pedidos']);
$admin->givePermissionTo(Permission::all());
$editor->givePermissionTo(['criar produto', 'editar produto']);
// Atribuir role ao usuário
$usuario->assignRole('editor');
$usuario->givePermissionTo('ver pedidos');
// Verificações
$usuario->hasRole('admin');
$usuario->can('deletar produto');
$usuario->hasAnyRole(['admin', 'editor']);
// No Blade:
@role('admin')
<a href="/admin">Painel Admin</a>
@endrole
@hasanyrole('admin|editor')
<a href="/produtos/criar">Criar Produto</a>
@endhasanyrole
Resumo
| Conceito | Função |
|---|---|
Auth::attempt() |
Verifica credenciais e cria sessão |
Middleware auth |
Bloqueia rotas para não autenticados |
| Gates | Regras de autorização simples e pontuais |
| Policies | Autorização encapsulada por Model |
$this->authorize() |
Verifica policy — lança 403 se negado |
@can / @cannot |
Verifica autorização no Blade |
| spatie/permission | Roles e permissions para sistemas complexos |
Exercício da semana
-
Implemente autenticação completa sem Breeze: login, logout, registro, proteção de rotas. Use
Auth::attempt()esession()->regenerate()manualmente. -
Crie uma
PedidoPolicycom métodosview,create,update,cancel. Um usuário só pode ver e cancelar seus próprios pedidos. Admins podem tudo. -
Instale
spatie/laravel-permission. Crie roles:admin,vendedor,cliente. Defina permissions granulares. Crie um seeder que cria os roles e um admin inicial. -
Desafio: implemente autenticação de dois fatores (2FA) simples: após login com senha, se o usuário tiver 2FA ativado, redirecione para uma tela de código TOTP. Use o pacote
pragmarx/google2fa-laravel.
Referências
- Laravel Authentication: https://laravel.com/docs/authentication
- Laravel Authorization: https://laravel.com/docs/authorization
- Spatie Laravel Permission: https://spatie.be/docs/laravel-permission
- Laravel Breeze: https://laravel.com/docs/starter-kits#laravel-breeze