8. Autenticación y Autorización en Laravel
Introducción
Section titled “Introducción”La autenticación y autorización son aspectos fundamentales en cualquier aplicación web moderna. Laravel ofrece un sistema robusto y flexible para gestionar estos procesos de manera segura y eficiente. En esta guía, exploraremos las diferentes opciones que Laravel proporciona para implementar autenticación y autorización en nuestras aplicaciones.
Laravel Breeze, Jetstream y Fortify
Section titled “Laravel Breeze, Jetstream y Fortify”Laravel ofrece tres paquetes principales para implementar autenticación de manera rápida y segura.
Laravel Breeze
Section titled “Laravel Breeze”Breeze es una implementación mínima y sencilla del sistema de autenticación de Laravel, ideal para proyectos nuevos o pequeños.
composer require laravel/breeze --devphp artisan breeze:installCaracterísticas principales:
- Implementación ligera con Blade y Tailwind CSS
- Registro y login de usuarios
- Verificación de email
- Restablecimiento de contraseña
- Fácil de personalizar y extender
Laravel Jetstream
Section titled “Laravel Jetstream”Jetstream proporciona una implementación más robusta con características avanzadas para aplicaciones que requieren mayor seguridad y funcionalidad.
composer require laravel/jetstreamphp artisan jetstream:install livewireCaracterísticas principales:
- Dos stacks de frontend: Livewire (Blade) o Inertia (Vue/React)
- Autenticación de dos factores
- Gestión de sesiones del navegador
- Soporte para equipos y permisos
- Verificación de email
- Gestión de perfil con foto
- Términos y condiciones
// Instalar con soporte para equiposphp artisan jetstream:install livewire --teams
// O con Inertia.jsphp artisan jetstream:install inertia --teamsLaravel Fortify
Section titled “Laravel Fortify”Fortify es un backend de autenticación sin interfaz de usuario, ideal para proyectos donde se necesita un control total sobre el frontend.
composer require laravel/fortifyphp artisan vendor:publish --provider="Laravel\Fortify\FortifyServiceProvider"Características principales:
- Backend de autenticación sin opiniones sobre el frontend
- Registro y login de usuarios
- Autenticación de dos factores
- Actualización de perfil y contraseña
- Restablecimiento de contraseña
- Verificación de email
// En config/app.php, agregar el proveedor de servicios'providers' => [ // ... AppProvidersFortifyServiceProvider::class,],Registro, login y logout
Section titled “Registro, login y logout”Independientemente del paquete que elijas, Laravel proporciona una API consistente para manejar la autenticación de usuarios.
Registro de usuarios
Section titled “Registro de usuarios”En una aplicación con Breeze o Jetstream, el registro ya está implementado. Si necesitas personalizarlo o implementarlo manualmente:
// En un controladorpublic function register(Request $request){ $request->validate([ 'name' => 'required|string|max:255', 'email' => 'required|string|email|max:255|unique:users', 'password' => 'required|string|min:8|confirmed', ]);
$user = User::create([ 'name' => $request->name, 'email' => $request->email, 'password' => Hash::make($request->password), ]);
// Autenticar al usuario inmediatamente después del registro Auth::login($user);
return redirect()->intended('dashboard');}Login de usuarios
Section titled “Login de usuarios”El proceso de login verifica las credenciales del usuario y crea una sesión:
// En un controladorpublic function login(Request $request){ $credentials = $request->validate([ 'email' => 'required|email', 'password' => 'required', ]);
if (Auth::attempt($credentials, $request->boolean('remember'))) { $request->session()->regenerate(); return redirect()->intended('dashboard'); }
return back()->withErrors([ 'email' => 'Las credenciales proporcionadas no coinciden con nuestros registros.', ]);}Logout de usuarios
Section titled “Logout de usuarios”Para cerrar la sesión de un usuario:
// En un controladorpublic function logout(Request $request){ Auth::logout();
$request->session()->invalidate(); $request->session()->regenerateToken();
return redirect('/login');}Middleware auth, guest y can
Section titled “Middleware auth, guest y can”Laravel utiliza middleware para proteger rutas y controlar el acceso a diferentes partes de la aplicación.
Middleware auth
Section titled “Middleware auth”El middleware auth asegura que solo los usuarios autenticados puedan acceder a ciertas rutas:
// En routes/web.phpRoute::middleware('auth')->group(function () { Route::get('/dashboard', function () { return view('dashboard'); });
Route::get('/profile', [ProfileController::class, 'edit'])->name('profile.edit');});
// O en un solo endpointRoute::get('/settings', function () { // Solo usuarios autenticados})->middleware('auth');Middleware guest
Section titled “Middleware guest”El middleware guest redirige a los usuarios ya autenticados, útil para páginas como login o registro:
// En routes/web.phpRoute::middleware('guest')->group(function () { Route::get('/login', [AuthController::class, 'showLoginForm'])->name('login'); Route::get('/register', [AuthController::class, 'showRegistrationForm'])->name('register');});
// Si un usuario autenticado intenta acceder a estas rutas, será redirigido a la ruta definida en RouteServiceProvider::HOMEMiddleware can
Section titled “Middleware can”El middleware can verifica si un usuario tiene un permiso específico:
// En routes/web.phpRoute::get('/posts/{post}/edit', [PostController::class, 'edit'])->middleware('can:update,post');
// También puedes usarlo en gruposRoute::middleware(['auth', 'can:manage-posts'])->group(function () { Route::get('/posts/create', [PostController::class, 'create']); Route::post('/posts', [PostController::class, 'store']);});
// O con un GateRoute::get('/admin/reports', function () { // Solo usuarios con permiso para ver reportes})->middleware('can:view-reports');Políticas (make:policy)
Section titled “Políticas (make:policy)”Las políticas en Laravel son clases que organizan la lógica de autorización para un modelo o recurso específico.
Crear una política
Section titled “Crear una política”php artisan make:policy PostPolicy --model=PostEsto generará una clase PostPolicy en app/Policies con métodos para cada acción CRUD.
Estructura de una política
Section titled “Estructura de una política”<?php
namespace AppPolicies;
use AppModelsPost;use AppModelsUser;use IlluminateAuthAccessHandlesAuthorization;
class PostPolicy{ use HandlesAuthorization;
/** * Determine if the user can view any posts. */ public function viewAny(User $user): bool { return true; // Todos los usuarios autenticados pueden ver posts }
/** * Determine if the user can view the post. */ public function view(User $user, Post $post): bool { return true; // Todos los usuarios autenticados pueden ver un post específico }
/** * Determine if the user can create posts. */ public function create(User $user): bool { return true; // Todos los usuarios autenticados pueden crear posts }
/** * Determine if the user can update the post. */ public function update(User $user, Post $post): bool { return $user->id === $post->user_id; // Solo el autor puede actualizar }
/** * Determine if the user can delete the post. */ public function delete(User $user, Post $post): bool { return $user->id === $post->user_id || $user->isAdmin(); // Autor o admin }
/** * Determine if the user can restore the post. */ public function restore(User $user, Post $post): bool { return $user->isAdmin(); // Solo admin puede restaurar }
/** * Determine if the user can permanently delete the post. */ public function forceDelete(User $user, Post $post): bool { return $user->isAdmin(); // Solo admin puede eliminar permanentemente }}Registrar políticas
Section titled “Registrar políticas”Las políticas se registran en el AuthServiceProvider:
<?php
namespace AppProviders;
use AppModelsPost;use AppPoliciesPostPolicy;use IlluminateFoundationSupportProvidersAuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider{ /** * The policy mappings for the application. * * @var array<class-string, class-string> */ protected $policies = [ Post::class => PostPolicy::class, ];
/** * Register any authentication / authorization services. */ public function boot(): void { $this->registerPolicies();
// Definir Gates aquí si es necesario }}Usar políticas en controladores
Section titled “Usar políticas en controladores”public function update(Request $request, Post $post){ // Autorizar la acción $this->authorize('update', $post);
// Continuar con la actualización si está autorizado $post->update($request->validated());
return redirect()->route('posts.show', $post);}Gates (Gate::define)
Section titled “Gates (Gate::define)”Los Gates son cierres simples que determinan si un usuario está autorizado a realizar una acción específica. Son útiles para lógica de autorización que no está necesariamente vinculada a un modelo.
Definir Gates
Section titled “Definir Gates”Los Gates se definen en el método boot del AuthServiceProvider:
<?php
namespace AppProviders;
use IlluminateSupportFacadesGate;use IlluminateFoundationSupportProvidersAuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider{ // ...
public function boot(): void { $this->registerPolicies();
// Gate simple Gate::define('view-dashboard', function ($user) { return $user->is_admin || $user->is_staff; });
// Gate con parámetros adicionales Gate::define('update-post', function ($user, $post) { return $user->id === $post->user_id; });
// Gate usando una clase y método Gate::define('moderate-posts', [PostModerationService::class, 'canModerate']);
// Gate con respuesta personalizada Gate::define('publish-article', function ($user, $article) { if (! $article->isComplete()) { return $this->deny('El artículo no está completo.'); }
return $user->hasRole('editor'); });
// Gate para superadmin que puede hacer todo Gate::before(function ($user, $ability) { if ($user->isSuperAdmin()) { return true; } }); }}Usar Gates
Section titled “Usar Gates”Puedes verificar Gates de varias formas:
// En controladorespublic function viewDashboard(){ if (Gate::allows('view-dashboard')) { // Usuario autorizado }
if (Gate::denies('view-dashboard')) { // Usuario no autorizado }
// Lanzar excepción si no está autorizado Gate::authorize('view-dashboard');
// Con parámetros adicionales if (Gate::allows('update-post', $post)) { // Usuario puede actualizar este post }}
// En Blade@if (Gate::allows('view-dashboard')) <a href="/dashboard">Ver Dashboard</a>@endif
@can('update-post', $post) <a href="/posts/{{ $post->id }}/edit">Editar</a>@endcan
// Con el helper can()if (auth()->user()->can('view-dashboard')) { // Usuario autorizado}
// O con el helper cannot()if (auth()->user()->cannot('delete-post', $post)) { // Usuario no autorizado}Combinando Políticas y Gates
Section titled “Combinando Políticas y Gates”Puedes combinar políticas y gates para crear un sistema de autorización completo:
// En AuthServiceProviderpublic function boot(): void{ $this->registerPolicies();
// Gates para permisos generales Gate::define('access-admin', function ($user) { return $user->hasRole('admin'); });
Gate::define('manage-users', function ($user) { return $user->hasPermission('users.manage'); });
// Las políticas se encargan de los permisos específicos de modelos // PostPolicy, UserPolicy, etc.}Conclusión
Section titled “Conclusión”Laravel ofrece un sistema de autenticación y autorización completo y flexible que se adapta a las necesidades de cualquier aplicación. Desde soluciones rápidas como Breeze hasta implementaciones más robustas como Jetstream, pasando por el control total con Fortify, Laravel proporciona las herramientas necesarias para proteger tu aplicación y gestionar permisos de usuario de manera eficiente.
Recuerda que la seguridad es un aspecto fundamental de cualquier aplicación web, y Laravel te ayuda a implementarla de manera correcta y segura.