Las políticas de acceso te permitirán de una manera increíblemente fácil, limitar y bloquear el acceso a ciertas partes de la aplicación. Cuando programamos, parte de lo que realmente queremos, es que los métodos de nuestros controladores no sean mayores a las veinte (20) líneas y esto lo logramos aislando fragmentos de código en otros archivos, como por ejemplo validaciones, consultas, políticas y así.
Vamos a aprender en este tutorial cómo aislar el bloque de código respecto a las políticas de acceso.
¿Cuando usamos este feature?
Ejemplo: Un usuario ha creado los artículos con ID 1, 2 y 3, otro usuario ha creado los artículos con ID 4 y 5, entonces crearíamos una política de acceso para que cada usuario solo pueda editar y borrar sus artículos y no los de otro usuario.
Comencemos
Instala un proyecto «comencemos desde cero con un proyecto en blanco», hazlo y vuelve para que a continuación creemos las tablas y así paso a paso cada archivo necesario para comprender completamente este feature.
Lo primero son las migraciones
Vamos a crear la migración POST php artisan make:model Post --migration con este comando creamos el modelo y la migración de ese modelo, la de usuarios no la ejecutamos porque ya viene instalada en Laravel 🙂
Clase CreateUsersTable método up()
1 2 3 4 5 6 7 8 9 10 11 | public function up() { Schema::create('users', function (Blueprint $table) { $table->increments('id'); $table->string('name', 128); $table->string('email', 128)->unique(); $table->string('password', 64); $table->rememberToken(); $table->timestamps(); }); } |
Clase CreatePostsTable método up()
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | public function up() { Schema::create('posts', function (Blueprint $table) { $table->increments('id'); $table->string('title', 128); $table->text('body'); $table->integer('user_id')->unsigned(); $table->timestamps(); $table->foreign('user_id')->references('id')->on('users') ->onDelete('cascade') ->onUpdate('cascade'); }); } |
Lo que sigue es tener datos para hacer pruebas (datos falsos o de semilla), para ello configuramos los seeds y factory.
Los seeders se crean con el siguiente comando, ejecuta ambos
php artisan make:seeder UserTableSeeder
php artisan make:seeder PostTableSeeder
Rimorsoft/database/seeds/UsersTableSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 | <?php use Illuminate\Database\Seeder; use Rimorsoft\User; class UsersTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { User::create([ 'name' => 'Italo Morales', 'email' => 'i@italomoralesf.com', 'password' => bcrypt(123456), ]); factory(User::class, 49)->create(); } } |
Rimorsoft/database/seeds/PostsTableSeeder.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 | <?php use Illuminate\Database\Seeder; use Rimorsoft\Post; class PostsTableSeeder extends Seeder { /** * Run the database seeds. * * @return void */ public function run() { factory(Post::class, 300)->create(); } } |
Rimorsoft/database/factories/ModelFactory.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 | <?php $factory->define(Rimorsoft\User::class, function (Faker\Generator $faker) { return [ 'name' => $faker->name, 'email' => $faker->safeEmail, 'password' => bcrypt(str_random(10)), 'remember_token' => str_random(10), ]; }); $factory->define(Rimorsoft\Post::class, function (Faker\Generator $faker) { return [ 'title' => $faker->sentence(3), 'body' => '<p>' . $faker->text(rand(400,800)) . '</p>' . '<p>' . $faker->text(rand(400,800)) . '</p>', 'user_id' => rand(1,50), ]; }); |
Esto ya lo sabías 🙂 lo siguiente que debes hacer ahora es configurar los datos de la base de datos en el archivo .env y ejecutar el comando php artisan migrate:refresh --seed
Ejemplo del archivo .env
1 2 3 4 5 6 | DB_CONNECTION=mysql DB_HOST=127.0.0.1 DB_PORT=3306 DB_DATABASE=policies DB_USERNAME=root DB_PASSWORD=root |
¿Creamos la política de acceso?
A eso viniste, así que manos a la obra. Ejecuta el siguiente comando para crear el archivo de políticas de acceso. php artisan make:policy PostPolicy Recuerda que la idea es aislar y crear la lógica correspondiente.
Esto crea una carpeta y dentro el archivo correspondiente a la política de acceso
Rimorsoft/app/Policies/PostPolicy.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 | <?php namespace Rimorsoft\Policies; use Rimorsoft\User; use Rimorsoft\Post; use Illuminate\Auth\Access\HandlesAuthorization; class PostPolicy { use HandlesAuthorization; /** * Create a new policy instance. * * @return void */ public function __construct() { // } public function pass(User $user, Post $post) { return $user->id == $post->user_id; } } |
Viene la parte donde damos de alta o hacemos saber que estos archivos existen, esto se hace dentro del ServiceProvider Rimorsoft/app/Providers/AuthServiceProvider.php
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 | <?php namespace Rimorsoft\Providers; Use Rimorsoft\Post; use Rimorsoft\Policies\PostPolicy; use Illuminate\Support\Facades\Gate; use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; class AuthServiceProvider extends ServiceProvider { /** * The policy mappings for the application. * * @var array */ protected $policies = [ Post::class => PostPolicy::class ]; /** * Register any authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); // } } |
Esta es la configuración necesaria para hacer uso de las políticas de acceso, ahora lo que debemos hacer es el llamado de esta configuración donde queremos aplicarlo 🙂 vamos con el código, nota que vamos a configurar los métodos edit y destroy.
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 | <?php namespace Rimorsoft\Http\Controllers\Backend; use Illuminate\Http\Request; use Rimorsoft\Http\Requests; use Rimorsoft\Http\Controllers\Controller; class PostController extends Controller { /** * Display the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function show($id) { $post = Rimorsoft\Post::find($id); $this->authorize('pass', $post); //lógica... retornar la vista } /** * Show the form for editing the specified resource. * * @param int $id * @return \Illuminate\Http\Response */ public function edit($id) { $post = Rimorsoft\Post::find($id); $this->authorize('pass', $post); //lógica... retornar la vista } /** * Update the specified resource in storage. * * @param \Illuminate\Http\Request $request * @param int $id * @return \Illuminate\Http\Response */ public function update(Request $request, $id) { $post = Rimorsoft\Post::find($id); $this->authorize('pass', $post); //lógica de actualizar } /** * Remove the specified resource from storage. * * @param int $id * @return \Illuminate\Http\Response */ public function destroy($id) { $post = Rimorsoft\Post::find($id); $this->authorize('pass', $post); //lógica de borrar } } |
Como puedes observar, usamos esta línea de código $this->authorize('pass', $post); donde pass es el método (y puede llevar cualquier nombre) en el archivo de políticas y $post
representa a la entidad.
Lo que nadie te dice es que debes crear una vista llamada 403.blade.php dentro de la carpeta errors, y cuando esta condición no se cumpla el sistema mostrará esta vista, donde curiosamente siempre escribo «PARECE QUE HACES TRAMPA… XD»
1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 | <!DOCTYPE html> <html> <head> <title>Be right back.</title> <link href="https://fonts.googleapis.com/css?family=Lato:100" rel="stylesheet" type="text/css"> <style> html, body { height: 100%; } body { margin: 0; padding: 0; width: 100%; color: #B0BEC5; display: table; font-weight: 100; font-family: 'Lato'; } .container { text-align: center; display: table-cell; vertical-align: middle; } .content { text-align: center; display: inline-block; } .title { font-size: 72px; margin-bottom: 40px; } </style> </head> <body> <div class="container"> <div class="content"> <div class="title">Parece que haces trampa... XD</div> </div> </div> </body> </html> |
Con esto podemos concluir
Las políticas de acceso de tu sistema forman parte de la lógica natural; lógica que debemos hacer según la necesidad real, sin embargo, hay cosas comunes como el ejemplo planteado en este tutorial, entonces, en esos casos ¿por qué no hacerlo usando las políticas de acceso de Laravel? ademas nos ayuda con el orden y buenas practicas.
¿Qué te pareció? Haz la practica y coméntame como te fue con eso.