En este tutorial aprenderemos a implementar Bouncer en Laravel. Bouncer es una librería que nos permite administrar roles y habilidades en cualquier aplicación que use modelos del ORM Eloquent.
Para poder continuar con este tutorial es importante que primero revises el post Manejo de roles y habilidades en Eloquent con Bouncer donde aprenderás a instalar y configurar Bouncer.
Luego de instalar Laravel y Bouncer, copiado las migraciones y realizada la configuración necesaria, podemos comenzar a crear nuestro ejemplo. Recuerda que todos los pasos de instalación y configuración son explicados en el tutorial Manejo de roles y habilidades en Eloquent con Bouncer.
Para este tutorial crearemos una pequeña aplicación que contará con dos modelos: Post y Comment además del modelo User que ya incluye Laravel. A continuación te explico el funcionamiento de cada modelo:
Post: este modelo almacenará posts o publicaciones creadas por los usuarios.Comment: este modelo se encargará de almacenar los comentarios de las publicaciones.
También tendremos un rol y dos habilidades:
- El rol admin es asignado a los administradores y permite realizar todo tipo de acciones.
- La habilidad Create Post es asignada a los autores y permite crear posts.
- La habilidad Delete Comment es asignada a los autores al momento de crear un comentario y permite a dicho autor eliminar sus propios comentarios.
Básicamente, en nuestra aplicación los autores podrán crear posts o publicaciones y dejar comentarios en dichas publicaciones. Estos tienen el control de sus propios comentarios y pueden eliminarlos, siempre y cuando hayan sido creados por ellos mismos. Sólo los administradores pueden eliminar los comentarios de cualquier usuario.
Asegúrate de ejecutar php artisan make:auth antes de continuar, para activar la autenticación por defecto de Laravel.
Creando el modelo Post
Al inicio del tutorial mencionamos que usaremos dos modelos: Post y Comment. Como en este tutorial nos centraremos en la creación de los posts vamos primero a crear el modelo Post:
// Ejecuta el siguiente comando en la terminal: php artisan make:model Post -mc
Dentro del modelo Post agregamos:
class Post extends Model
{
protected $guarded = [];
public function comments()
{
return $this->hasMany(Comment::class);
}
public function user()
{
return $this->belongsTo(User::class);
}
}
También debemos editar el modelo User que viene por defecto con Laravel. Recuerda implementar el trait HasRolesAndAbilities que pertenece a Bouncer. En el modelo User agregaremos los métodos necesarios para la relación entre los usuarios y los posts:
class User extends Authenticatable
{
// ...
public function posts()
{
return $this->hasMany(Post::class);
}
}
Creando el seeder
En nuestro archivo DatabaseSeeder.php agregaremos dos usuarios y los almacenaremos en las variables $user y $creatorOfPosts:
<?php
use Bouncer;
use App\User;
class DatabaseSeeder extends Seeder
{
public function run()
{
$user = factory(User::class)->create([
'name' => 'Foo Bar',
'email' => '[email protected]',
'password' => bcrypt('secret')
]);
$creatorOfPosts = factory(User::class)->create([
'name' => 'Creator of Posts',
'email' => '[email protected]',
'password' => bcrypt('secret')
]);
}
}
No olvides importar los modelos y el alias Bouncer al principio del archivo.
En el mismo archivo DatabaseSeeder.php también crearemos y asignaremos el rol admin y la habilidad Create Post al segundo usuario que hemos creado:
<?php
//...
class DatabaseSeeder extends Seeder
{
public function run()
{
// ...
// Creamos el rol de administrador
Bouncer::allow('admin')->everything();
// Asignamos el rol de administrador a $user
$user->assign('admin');
// Asignamos al autor la habilidad de crear posts
$creatorOfPosts->allow('create', Post::class);
}
}
Luego de hacer esto podemos ejecutar las migraciones y los seeders con el comando php artisan migrate:refresh --seed.
Controladores
Para continuar con nuestra aplicación debemos agregar la lógica al controlador PostController. Este controlador fue creado automáticamente al generar el modelo Post (puesto que usamos la opción -c). A continuación vamos a agregar la lógica para listar y crear posts al controlador PostController.php:
class PostController extends Controller
{
public function index()
{
$posts = Post::paginate(10);
return view('posts.index', compact('posts'));
}
public function create()
{
return view('posts.create');
}
public function store(Request $request)
{
auth()->user()->posts()->create($request->all());
return redirect()->action('PostController@index');
}
public function show(Post $post)
{
return view('posts.show', compact('post'));
}
}
Rutas
En el archivo web.php vamos a agregar las rutas que nos van a permitir realizar las diferentes acciones en nuestra aplicación:
Route::group(['middleware' => 'auth'], function () {
Route::get('/home', 'PostController@index')->name('posts.index');
Route::group(['middleware' => 'can:create,App\Post'], function () {
Route::get('/posts/create', 'PostController@create')->name('posts.create');
Route::post('/posts', 'PostController@store')->name('posts.store');
});
});
Route::get('posts/{post}', 'PostController@show')->name('posts.show');
Observa como mediante can:create,App\Post protegemos las rutas para que sólo los autores que pueden crear posts puedan acceder a los recursos que permiten ejecutar dicha acción.
Vistas
Finalmente podemos agregar las vistas de nuestra aplicación. Dentro del directorio resources/views/posts agrega las siguientes vistas:
Archivo index.blade.php:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Posts</div>
<div class="card-body">
@foreach ($posts as $post)
<div class="card mb-3">
<div class="card-body">
<h3>
<a href="{{ route('posts.show', $post) }}">{{ $post->title }}</a>
</h3>
<hr>
{{ $post->body }}
</div>
</div>
@endforeach
</div>
</div>
</div>
</div>
</div>
@endsection
Archivo create.blade.php:
@extends('layouts.app')
@section('content')
<div class="container">
<div class="row justify-content-center">
<div class="col-md-8">
<div class="card">
<div class="card-header">Crear nuevo post</div>
<div class="card-body">
<form method="POST" action="{{ route('posts.store') }}">
@csrf
<div class="form-group">
<label for="title">Titulo</label>
<input type="text" class="form-control" name="title" required>
</div>
<div class="form-group">
<label for="body">Contenido</label>
<textarea name="body" class="form-control" cols="30" rows="10"></textarea>
</div>
<div class="form-group">
<button type="submit" class="btn btn-primary">Publicar</button>
</div>
</form>
</div>
</div>
</div>
</div>
</div>
@endsection
En el archivo resources/views/layouts/app.blade.php agregamos un enlace para la creación de los nuevos posts, esto lo hacemos dentro de la etiqueta ul ubicada después del comentario «Left Side Of Navbar», de esta forma:
<!-- Left Side Of Navbar -->
<ul class="navbar-nav mr-auto">
@can ('create', App\Post::class)
<li>
<a href="{{ route('posts.create') }}" class="nav-link">Crear Post</a>
</li>
@endcan
</ul>
Utilizando la directiva @can comprobamos si el usuario tiene la habilidad para crear posts.
Si tienes alguna pregunta o inquietud no dudes en dejarla en los comentarios. En el próximo tutorial agregaremos todo lo relacionado a los comentarios.
Puedes ver y descargar el código de este ejemplo en GitHub: laravel-bouncer-example.
Si te ha gustado este tutorial y te interesa el tema de manejo de roles y habilidades puedes ver una explicación detallada y a fondo en el curso Técnicas de Autorización con Laravel donde aprenderás no sólo a utilizar Bouncer sino también sobre muchos otros temas respecto al manejo de roles, permisos y autorización:
- Roles y permisos dinámicos en Laravel con Bouncer
- Propiedad de modelos con Bouncer en Laravel
- Definición de roles y habilidades mediante seeders con Laravel y Bouncer
- Uso de las directivas de autorización @can @cannot y @elsecan en Blade
No olvides seguirnos en Twitter y suscribirte a nuestro boletín:
Regístrate hoy en Styde y obtén acceso a todo nuestro contenido.
