() translation by (you can also view the original English article)
Hoy vamos a discutir el sistema de autorización del framework web Laravel. El marco de Laravel implementa la autorización en forma de puertas y políticas Después de una introducción a las puertas y políticas, demostraré los conceptos implementando un ejemplo personalizado.
Supongo que ya conoce el sistema de autenticación Laravel incorporado, ya que es algo esencial para comprender el concepto de autorización. Obviamente, el sistema de autorización funciona junto con el sistema de autenticación para identificar la sesión de usuario legítima.
Si no está al tanto del sistema de autenticación Laravel, le recomendaría encarecidamente consultar la documentación oficial, que le brinda una visión práctica del tema.
Enfoque de Laravel a la Autorización
A estas alturas, ya debe saber que el sistema de autorización de Laravel viene en dos tipos: puertas y políticas. Aunque parezca un asunto complicado, yo diría que es bastante fácil implementarlo una vez que lo aprenda.
Las puertas le permiten definir una regla de autorización utilizando un enfoque simple basado en el cierre. En otras palabras, cuando desea autorizar una acción que no está relacionada con ningún modelo específico, la puerta es el lugar perfecto para implementar esa lógica.
Echemos un vistazo rápido a cómo se ve la autorización basada en puerta:
1 |
...
|
2 |
...
|
3 |
Gate::define('update-post', function ($user, $post) { |
4 |
return $user->id == $post->user_id; |
5 |
});
|
6 |
...
|
7 |
...
|
El fragmento de código anterior define la actualización de la regla de autorización a la que puede llamar desde cualquier lugar de su aplicación.
Por otro lado, debe usar políticas cuando desee agrupar la lógica de autorización de cualquier modelo. Por ejemplo, supongamos que tiene un modelo de publicación en su aplicación y desea autorizar las acciones de CRUD de ese modelo. En ese caso, es la política que necesita implementar.
1 |
class PostPolicy |
2 |
{
|
3 |
public function view(User $user, Post $post) {} |
4 |
public function create(User $user) {} |
5 |
public function update(User $user, Post $post) {} |
6 |
public function delete(User $user, Post $post) {} |
7 |
}
|
Como puede ver, es una clase de política bastante simple que define la autorización para las acciones CRUD del modelo Post
.
Así que eso fue una introducción a las puertas y políticas en Laravel. A partir de la siguiente sección, veremos una demostración práctica de cada elemento.
Puertas
En esta sección, veremos un ejemplo practico para entender el concepto de puertas.
La mayoría de las veces, termina mirando al proveedor de servicios de Laravel cuando necesita registrar un componente o un servicio. Siguiendo esa convención, avancemos y definamos nuestra puerta personalizada en app/Providers/AuthServiceProvider.php
como se muestra en el siguiente fragmento de código.
1 |
<?php
|
2 |
namespace App\Providers; |
3 |
|
4 |
use Illuminate\Support\Facades\Gate; |
5 |
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; |
6 |
use Illuminate\Http\Request; |
7 |
|
8 |
class AuthServiceProvider extends ServiceProvider |
9 |
{
|
10 |
/**
|
11 |
* The policy mappings for the application.
|
12 |
*
|
13 |
* @var array
|
14 |
*/
|
15 |
protected $policies = [ |
16 |
'App\Model' => 'App\Policies\ModelPolicy', |
17 |
];
|
18 |
|
19 |
/**
|
20 |
* Register any authentication / authorization services.
|
21 |
*
|
22 |
* @return void
|
23 |
*/
|
24 |
public function boot() |
25 |
{
|
26 |
$this->registerPolicies(); |
27 |
|
28 |
Gate::define('update-post', function ($user, $post) { |
29 |
return $user->id == $post->user_id; |
30 |
});
|
31 |
}
|
32 |
}
|
En el método boot
, hemos definido nuestra puerta personalizada:
1 |
Gate::define('update-post', function ($user, $post) { |
2 |
return $user->id == $post->user_id; |
3 |
});
|
Al definir una puerta, toma un cierre que devuelve TRUE o FALSE según la lógica de autorización que está definida en la definición de la puerta. Aparte de la función de cierre, hay otras formas de definir puertas.
Por ejemplo, la siguiente definición de puerta llama a la acción del controlador en lugar de a la función de cierre.
1 |
Gate::define('update-post', 'ControllerName@MethodName'); |
Ahora, avancemos y agreguemos una ruta personalizada para que podamos ver una demostración de cómo funciona la autorización basada en puertas. En el archivo de rutas de routes/web.php
, agreguemos la siguiente ruta.
1 |
Route::get('service/post/gate', 'PostController@gate'); |
Vamos a crear un archivo de controlador asociado app/Http/Controllers/PostController.php
también.
1 |
<?php
|
2 |
namespace App\Http\Controllers; |
3 |
|
4 |
use App\Http\Controllers\Controller; |
5 |
use App\Post; |
6 |
use Illuminate\Support\Facades\Gate; |
7 |
|
8 |
class PostController extends Controller |
9 |
{
|
10 |
/* Make sure you don't user Gate and Policy altogether for the same Model/Resource */
|
11 |
public function gate() |
12 |
{
|
13 |
$post = Post::find(1); |
14 |
|
15 |
if (Gate::allows('update-post', $post)) { |
16 |
echo 'Allowed'; |
17 |
} else { |
18 |
echo 'Not Allowed'; |
19 |
}
|
20 |
|
21 |
exit; |
22 |
}
|
23 |
}
|
En la mayoría de los casos, terminará utilizando el método de allows
o denies
de la fachada del Gate
para autorizar una determinada acción. En nuestro ejemplo anterior, hemos utilizado el método allows
para verificar si el usuario actual puede realizar la acción de update-post
.
Los usuarios con ojos agudos habrían notado que solo hemos pasado el segundo argumento $post
al cierre. El primer argumento, el usuario registrado actual, se inyecta automáticamente por la fachada del Gate
.
Así es como se supone que debes usar gates para autorizar acciones en tu aplicación Laravel. La siguiente sección trata sobre cómo usar las políticas, si desea implementar la autorización para sus modelos.
Políticas
Como comentamos anteriormente, cuando desea agrupar lógicamente sus acciones de autorización para cualquier modelo o recurso en particular, es la política que está buscando.
En esta sección, crearemos una política para el modelo de publicación que se utilizará para autorizar todas las acciones de CRUD. Supongo que ya ha implementado el modelo Post en su aplicación; De lo contrario, algo similar hará.
El comando Laravel Artisan
es tu mejor amigo cuando se trata de crear un código de apéndice. Puede utilizar el siguiente comando de Artisan para crear una política para el modelo de publicación.
1 |
$php artisan make:policy PostPolicy --model=Post |
Como puede ver, hemos suministrado el argumento --model = Post
para que cree todos los métodos CRUD. A falta de eso, se creará una clase de política en blanco. Puede ubicar la clase de política recién creada en app/Policies/PostPolicy.php.
Vamos a reemplazarlo con el siguiente código.
1 |
<?php
|
2 |
namespace App\Policies; |
3 |
|
4 |
use App\User; |
5 |
use App\Post; |
6 |
use Illuminate\Auth\Access\HandlesAuthorization; |
7 |
|
8 |
class PostPolicy |
9 |
{
|
10 |
use HandlesAuthorization; |
11 |
|
12 |
/**
|
13 |
* Determine whether the user can view the post.
|
14 |
*
|
15 |
* @param \App\User $user
|
16 |
* @param \App\Post $post
|
17 |
* @return mixed
|
18 |
*/
|
19 |
public function view(User $user, Post $post) |
20 |
{
|
21 |
return TRUE; |
22 |
}
|
23 |
|
24 |
/**
|
25 |
* Determine whether the user can create posts.
|
26 |
*
|
27 |
* @param \App\User $user
|
28 |
* @return mixed
|
29 |
*/
|
30 |
public function create(User $user) |
31 |
{
|
32 |
return $user->id > 0; |
33 |
}
|
34 |
|
35 |
/**
|
36 |
* Determine whether the user can update the post.
|
37 |
*
|
38 |
* @param \App\User $user
|
39 |
* @param \App\Post $post
|
40 |
* @return mixed
|
41 |
*/
|
42 |
public function update(User $user, Post $post) |
43 |
{
|
44 |
return $user->id == $post->user_id; |
45 |
}
|
46 |
|
47 |
/**
|
48 |
* Determine whether the user can delete the post.
|
49 |
*
|
50 |
* @param \App\User $user
|
51 |
* @param \App\Post $post
|
52 |
* @return mixed
|
53 |
*/
|
54 |
public function delete(User $user, Post $post) |
55 |
{
|
56 |
return $user->id == $post->user_id; |
57 |
}
|
58 |
}
|
Para poder utilizar nuestra clase Policy, debemos registrarla utilizando el proveedor de servicios Laravel como se muestra en el siguiente fragmento de código.
1 |
<?php
|
2 |
namespace App\Providers; |
3 |
|
4 |
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider; |
5 |
use Illuminate\Http\Request; |
6 |
use App\Post; |
7 |
use App\Policies\PostPolicy; |
8 |
|
9 |
class AuthServiceProvider extends ServiceProvider |
10 |
{
|
11 |
/**
|
12 |
* The policy mappings for the application.
|
13 |
*
|
14 |
* @var array
|
15 |
*/
|
16 |
protected $policies = [ |
17 |
'App\Model' => 'App\Policies\ModelPolicy', |
18 |
Post::class => PostPolicy::class |
19 |
];
|
20 |
|
21 |
/**
|
22 |
* Register any authentication / authorization services.
|
23 |
*
|
24 |
* @return void
|
25 |
*/
|
26 |
public function boot() |
27 |
{
|
28 |
$this->registerPolicies(); |
29 |
}
|
30 |
}
|
Hemos agregado el mapeo de nuestra Policy en la propiedad $policies
. Le dice a Laravel que llame al método de política correspondiente para autorizar la acción CRUD.
También debe registrar las políticas utilizando el método registerPolicies
, como lo hemos hecho en el método boot
.
Continuando, creemos un par de rutas personalizadas en el archivo route/web.php
para que podamos probar nuestros métodos de Política allí.
1 |
Route::get('service/post/view', 'PostController@view'); |
2 |
Route::get('service/post/create', 'PostController@create'); |
3 |
Route::get('service/post/update', 'PostController@update'); |
4 |
Route::get('service/post/delete', 'PostController@delete'); |
Finalmente, creemos un controlador asociado en app/Http/Controllers/PostController.php.
1 |
<?php
|
2 |
namespace App\Http\Controllers; |
3 |
|
4 |
use App\Http\Controllers\Controller; |
5 |
use App\Post; |
6 |
use Illuminate\Support\Facades\Auth; |
7 |
|
8 |
class PostController extends Controller |
9 |
{
|
10 |
public function view() |
11 |
{
|
12 |
// get current logged in user
|
13 |
$user = Auth::user(); |
14 |
|
15 |
// load post
|
16 |
$post = Post::find(1); |
17 |
|
18 |
if ($user->can('view', $post)) { |
19 |
echo "Current logged in user is allowed to update the Post: {$post->id}"; |
20 |
} else { |
21 |
echo 'Not Authorized.'; |
22 |
}
|
23 |
}
|
24 |
|
25 |
public function create() |
26 |
{
|
27 |
// get current logged in user
|
28 |
$user = Auth::user(); |
29 |
|
30 |
if ($user->can('create', Post::class)) { |
31 |
echo 'Current logged in user is allowed to create new posts.'; |
32 |
} else { |
33 |
echo 'Not Authorized'; |
34 |
}
|
35 |
|
36 |
exit; |
37 |
}
|
38 |
|
39 |
public function update() |
40 |
{
|
41 |
// get current logged in user
|
42 |
$user = Auth::user(); |
43 |
|
44 |
// load post
|
45 |
$post = Post::find(1); |
46 |
|
47 |
if ($user->can('update', $post)) { |
48 |
echo "Current logged in user is allowed to update the Post: {$post->id}"; |
49 |
} else { |
50 |
echo 'Not Authorized.'; |
51 |
}
|
52 |
}
|
53 |
|
54 |
public function delete() |
55 |
{
|
56 |
// get current logged in user
|
57 |
$user = Auth::user(); |
58 |
|
59 |
// load post
|
60 |
$post = Post::find(1); |
61 |
|
62 |
if ($user->can('delete', $post)) { |
63 |
echo "Current logged in user is allowed to delete the Post: {$post->id}"; |
64 |
} else { |
65 |
echo 'Not Authorized.'; |
66 |
}
|
67 |
}
|
68 |
}
|
Hay diferentes formas en que puede autorizar sus acciones utilizando las Políticas. En nuestro ejemplo anterior, hemos utilizado el modelo User
para autorizar nuestras acciones de modelo Post
.
El modelo User proporciona dos métodos útiles para fines de autorización: can
y cant
. El método can
se usa para verificar si el usuario actual es capaz de ejecutar una determinada acción. Y la contraparte del método can
, el método cant
, se utiliza para determinar la incapacidad de la ejecución de la acción.
Tomemos el fragmento del método view
del controlador para ver qué hace exactamente.
1 |
public function view() |
2 |
{
|
3 |
// get current logged in user
|
4 |
$user = Auth::user(); |
5 |
|
6 |
// load post
|
7 |
$post = Post::find(1); |
8 |
|
9 |
if ($user->can('view', $post)) { |
10 |
echo "Current logged in user is allowed to update the Post: {$post->id}"; |
11 |
} else { |
12 |
echo 'Not Authorized.'; |
13 |
}
|
14 |
}
|
En primer lugar, cargamos al usuario que ha iniciado sesión actualmente, lo que nos da el objeto del modelo de User. A continuación, cargamos una publicación de ejemplo utilizando el modelo de publicación.
Avanzando, hemos utilizado el método can
del modelo de User para autorizar la acción de view
del modelo Post
. El primer argumento del método can
es el nombre de la acción que desea autorizar, y el segundo argumento es el objeto modelo contra el que desea obtener autorización.
That was a demonstration of how to use the User
model to authorize the actions using policies. Alternatively, you could use the Controller Helper as well, if you’re in the controller while authorizing a certain action.
1 |
…
|
2 |
$this->authorize('view', $post); |
3 |
…
|
Como puede ver, no necesita cargar el modelo User si usa el Controller Helper.
Así que ese era el concepto de políticas a su disposición, y es realmente útil para autorizar un modelo o un recurso, ya que le permite agrupar la lógica de autorización en un solo lugar.
Solo asegúrate de no usar puertas y políticas por completo para las mismas acciones del Model, de lo contrario, se crearán problemas. Eso es de mi parte por hoy, ¡y lo dejare por hoy!
Conclusión
Hoy, fue la autorización de Laravel la que ocupó el centro de mi artículo. Al comienzo del artículo, presenté los elementos principales de la autorización, puertas y políticas de Laravel.
Después de eso, pasamos por la creación de nuestra puerta y política personalizadas para ver cómo funciona en el mundo real. Espero que hayas disfrutado el artículo y hayas aprendido algo útil en el contexto de Laravel.
Para aquellos de ustedes que ya están comenzando con Laravel o que desean ampliar sus conocimientos, sitio o aplicación con extensiones, tenemos una variedad de cosas que puede estudiar en Envato Market.
¡Como siempre, me encantaría saber mas de ti en los comentarios de abajo!