Autorización
- Introducción
- Gates
- Creación de policies
- Escritura de policies
- Autorización de acciones mediante policies
Introducción
Además de proporcionar servicios de autenticación incorporados, Laravel también proporciona una forma sencilla de autorizar las acciones del usuario contra un recurso determinado. Por ejemplo, aunque un usuario esté autenticado, puede que no esté autorizado a actualizar o borrar ciertos modelos de Eloquent o registros de bases de datos gestionados por tu aplicación. Las características de autorización de Laravel proporcionan una forma fácil y organizada de gestionar este tipo de comprobaciones de autorización.
Laravel proporciona dos formas principales de autorizar acciones: gates y policies. Piensa en las gates y las policies como rutas y controladores. Las gates proporcionan un enfoque simple, con una autorización basada en un closure, mientras que policies, como los controladores, agrupan la lógica en torno a un modelo o recurso en particular. En esta sección, exploraremos primero las gates
y luego examinaremos las policies
.
A la hora de crear una aplicación, no es necesario elegir entre el uso exclusivo de gates o el uso exclusivo de policies. Lo más probable es que la mayoría de las aplicaciones contengan una mezcla de gates y policies, ¡y eso está perfectamente bien! Las gates son más aplicables a acciones que no están relacionadas con ningún modelo o recurso, como ver un panel de control del administrador. Por el contrario, las policies deben utilizarse cuando se desea autorizar una acción para un modelo o recurso en particular.
Gates
Escritura de Gates
Advertencia
Las gates son una buena forma de aprender los fundamentos de autorización de Laravel, sin embargo, cuando se esta construyendo una applicación robusta, debe considerar el uso de policies para organizar sus reglas de autorización.
Las gates son simples closures que determinan si un usuario está autorizado a realizar una acción determinada. Típicamente, las gates se definen dentro del método boot
de la clase App\Providers\AuthServiceProvider
usando la facade Gate
. Las gates siempre reciben una instancia de usuario como su primer argumento y, de manera opcional, pueden recibir argumentos adicionales como un modelo de Eloquent.
En este ejemplo, definiremos una gate para determinar si un usuario puede actualizar un modelo App\Models\Post
dado. La gate logrará esto comparando el id
del usuario con el user_id
del usuario que creó el post:
use App\Models\Post;use App\Models\User;use Illuminate\Support\Facades\Gate; /** * Register any authentication / authorization services. * * @return void */public function boot(){ $this->registerPolicies(); Gate::define('update-post', function (User $user, Post $post) { return $user->id === $post->user_id; });}
Al igual que los controladores, las gates también pueden definirse utilizando un "array callback" con una clase y uno de sus métodos públicos:
use App\Policies\PostPolicy;use Illuminate\Support\Facades\Gate; /** * Register any authentication / authorization services. * * @return void */public function boot(){ $this->registerPolicies(); Gate::define('update-post', [PostPolicy::class, 'update']);}
Autorización de acciones
Para autorizar una acción usando gates, deberías usar los métodos allows
o denies
proporcionados por la facade la Gate
. Ten en cuenta que no es necesario que pases el usuario autenticado a estos métodos. Laravel se encargará automáticamente de pasar el usuario al closure del gate. Es típico llamar a los métodos de autorización de gate dentro de los controladores de tu aplicación antes de realizar una acción que requiera autorización:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Models\Post;use Illuminate\Http\Request;use Illuminate\Support\Facades\Gate; class PostController extends Controller{ /** * Update the given post. * * @param \Illuminate\Http\Request $request * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function update(Request $request, Post $post) { if (! Gate::allows('update-post', $post)) { abort(403); } // Update the post... }}
Si desea determinar si un usuario distinto del usuario autenticado actualmente está autorizado a realizar una acción, puede utilizar el método forUser
en la facade de la gate
:
if (Gate::forUser($user)->allows('update-post', $post)) { // The user can update the post...} if (Gate::forUser($user)->denies('update-post', $post)) { // The user can't update the post...}
Puede autorizar múltiples acciones a la vez utilizando los métodos any
o none
:
if (Gate::any(['update-post', 'delete-post'], $post)) { // The user can update or delete the post...} if (Gate::none(['update-post', 'delete-post'], $post)) { // The user can't update or delete the post...}
Autorizar o lanzar excepciones
Si desea intentar autorizar una acción y lanzar automáticamente una Illuminate\Auth\Access\AuthorizationException
si el usuario no está autorizado a realizar la acción dada, puede utilizar el método authorize
de la facade la gate
. Las instancias de AuthorizationException
se convierten automáticamente en una respuesta HTTP 403 por el gestor de excepciones de Laravel:
Gate::authorize('update-post', $post); // The action is authorized...
Suministro de contexto adicional
Los métodos gate para autorizar habilidades (allows
, denies
, check
, any
, none
, authorize
, can
, cannot
) y las directivas Blade de autorización (@can
, @cannot
, @canany
) pueden recibir un array como segundo argumento. Los elementos del array se pasan como parámetros al closure la gate y se pueden utilizar como contexto adicional al tomar decisiones de autorización:
use App\Models\Category;use App\Models\User;use Illuminate\Support\Facades\Gate; Gate::define('create-post', function (User $user, Category $category, $pinned) { if (! $user->canPublishToGroup($category->group)) { return false; } elseif ($pinned && ! $user->canPinPosts()) { return false; } return true;}); if (Gate::check('create-post', [$category, $pinned])) { // The user can create the post...}
Gates con Respuestas
Hasta ahora, sólo hemos examinado gates que devuelven valores booleanos simples. Sin embargo, a veces puede que desee devolver una respuesta más detallada, incluyendo un mensaje de error. Para ello, puede devolver una Illuminate\Auth\Access\Response
desde su gate:
use App\Models\User;use Illuminate\Auth\Access\Response;use Illuminate\Support\Facades\Gate; Gate::define('edit-settings', function (User $user) { return $user->isAdmin ? Response::allow() : Response::deny('You must be an administrator.');});
Incluso cuando devuelve una respuesta de autorización desde su gate, el método Gate::allows
devolverá un simple valor booleano; sin embargo, puede usar el método Gate::inspect
para obtener la respuesta de autorización completa devuelta por la gate:
$response = Gate::inspect('edit-settings'); if ($response->allowed()) { // The action is authorized...} else { echo $response->message();}
Cuando se utiliza el método Gate::authorize
, el cual lanza una AuthorizationException
si la acción no está autorizada, el mensaje de error proporcionado por la respuesta de autorización se propagará a la respuesta HTTP:
Gate::authorize('edit-settings'); // The action is authorized...
Personalizando el Estado de la Respuesta HTTP
Cuando se deniega una acción a través de una gate, se devuelve una respuesta HTTP 403
; sin embargo, a veces puede ser útil devolver un código de estado HTTP alternativo. Puede personalizar el código de estado HTTP devuelto por una comprobación de autorización fallida utilizando el constructor estático denyWithStatus
en la clase Illuminate\Auth\Access\Response
:
use App\Models\User;use Illuminate\Auth\Access\Response;use Illuminate\Support\Facades\Gate; Gate::define('edit-settings', function (User $user) { return $user->isAdmin ? Response::allow() : Response::denyWithStatus(404);});
Dado que ocultar recursos mediante una respuesta 404
es un patrón muy común en las aplicaciones web, el método denyAsNotFound
se ofrece para más comodidad:
use App\Models\User;use Illuminate\Auth\Access\Response;use Illuminate\Support\Facades\Gate; Gate::define('edit-settings', function (User $user) { return $user->isAdmin ? Response::allow() : Response::denyAsNotFound();});
Interceptación de comprobaciones Gate
A veces, es posible que desee conceder todas las capacidades a un usuario específico. Puede utilizar el método before
para definir un closure que se ejecute antes de todas las demás comprobaciones de autorización:
use Illuminate\Support\Facades\Gate; Gate::before(function ($user, $ability) { if ($user->isAdministrator()) { return true; }});
Si el closure before
devuelve un resultado no nulo, ese resultado se considerará el resultado de la comprobación de autorización.
Puede utilizar el método after
para definir un closure que se ejecute después de todas las demás comprobaciones de autorización:
Gate::after(function ($user, $ability, $result, $arguments) { if ($user->isAdministrator()) { return true; }});
De forma similar al método before
, si el closure after
devuelve un resultado no nulo, ese resultado se considerará el resultado de la comprobación de autorización.
Autorización Inline
Ocasionalmente, es posible que desee determinar si el usuario autenticado actualmente está autorizado a realizar una acción determinada sin escribir una gate dedicada que corresponda a la acción. Laravel permite realizar este tipo de comprobaciones de autorización "inline" mediante los métodos gate::allowIf
y gate::denyIf
:
use Illuminate\Support\Facades\Gate; Gate::allowIf(fn ($user) => $user->isAdministrator()); Gate::denyIf(fn ($user) => $user->banned());
Si la acción no está autorizada o si no hay ningún usuario autenticado, Laravel lanzará automáticamente una excepción Illuminate\Auth\Access\AuthorizationException
. Las instancias de AuthorizationException
se convierten automáticamente en una respuesta HTTP 403 por el gestor de excepciones de Laravel.
Creación de Policies
Generación de Policies
Las Policies son clases que organizan la lógica de autorización en torno a un modelo o recurso en particular. Por ejemplo, si su aplicación es un blog, puede tener un modelo App\Models\Post
y una correspondiente App\Policies\PostPolicy
para autorizar acciones de usuario como crear o actualizar posts.
Puede generar una policy utilizando el comando make:policy
de Artisan. La policy generada será colocada en el directorio app/Policies
. Si este directorio no existe en tu aplicación, Laravel lo creará por ti:
php artisan make:policy PostPolicy
El comando make:policy
generará una clase de policy vacía. Si deseas generar una clase con métodos de policy de ejemplo relacionados con la visualización, creación, actualización y eliminación del recurso, puedes proporcionar una opción --model
al ejecutar el comando:
php artisan make:policy PostPolicy --model=Post
Registro de Policies
Una vez creada la clase de policy, es necesario registrarla. Registrando policies es como podemos informar a Laravel qué policy usar cuando autoriza acciones contra un tipo de modelo dado.
El App\Providers\AuthServiceProvider
incluido con las nuevas aplicaciones Laravel contiene una propiedad policies
que mapea tus modelos Eloquent a sus correspondientes policies. El registro de una policy le indicará a Laravel qué policy utilizar cuando autorice acciones contra un modelo Eloquent dado:
<?php namespace App\Providers; use App\Models\Post;use App\Policies\PostPolicy;use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;use Illuminate\Support\Facades\Gate; class AuthServiceProvider extends ServiceProvider{ /** * The policy mappings for the application. * * @var array */ protected $policies = [ Post::class => PostPolicy::class, ]; /** * Register any application authentication / authorization services. * * @return void */ public function boot() { $this->registerPolicies(); // }}
Policy Auto-Discovery
En lugar de registrar manualmente policies, éstas pueden ser registradas automáticamente siempre que el modelo y la policy sigan las convenciones de nomenclatura estándar de Laravel. En concreto, las policies deben estar en un directorio llamado Policies
situado en el mismo nivel o uno por encima del directorio que contiene sus modelos. Así, por ejemplo, los modelos pueden colocarse en el directorio app/Models
mientras que las policies pueden colocarse en el directorio app/Policies
. En esta situación, Laravel buscará las policies en app/Models/Policies
y luego en app/Policies
. Además, el nombre de policy debe coincidir con el nombre del modelo y tener el sufijo Policy
. Así, un modelo User
correspondería a una clase de policy UserPolicy
.
Si desea definir su propia lógica de descubrimiento de policy, puede registrar un callback de descubrimiento de policy personalizado utilizando el método Gate::guessPolicyNamesUsing
. Normalmente, este método debería llamarse desde el método de boot
del AuthServiceProvider
de su aplicación:
use Illuminate\Support\Facades\Gate; Gate::guessPolicyNamesUsing(function ($modelClass) { // Return the name of the policy class for the given model...});
Advertencia
Cualquier policy que esté explícitamente asignada en elAuthServiceProvider
tendrá prioridad sobre cualquier policy potencialmente autodescubierta.
Escritura de policies
Métodos de una Policy
Una vez registrada la clase policy, puedes añadir métodos para cada acción que autorice. Por ejemplo, definamos un método update
en nuestro PostPolicy
que determine si una instancia de App\Models\User
dada puede actualizar una instancia de App\Models\Post
.
El método update
recibirá como argumentos una instancia de User
y una instancia de Post
, y debería devolver true
o false
indicando si el usuario está autorizado a actualizar el Post
dado. Así, en este ejemplo, verificaremos que el id
del usuario coincide con el user_id
de la entrada:
<?php namespace App\Policies; use App\Models\Post;use App\Models\User; class PostPolicy{ /** * Determine if the given post can be updated by the user. * * @param \App\Models\User $user * @param \App\Models\Post $post * @return bool */ public function update(User $user, Post $post) { return $user->id === $post->user_id; }}
Puede continuar definiendo métodos adicionales en la policy según sea necesario para las diversas acciones que autoriza. Por ejemplo, puede definir métodos view
o delete
para autorizar varias acciones relacionadas con Post
, pero recuerde que es libre de dar a los métodos de su policy el nombre que desee.
Si usted utilizó la opción --model
cuando generó su policy a través de la consola Artisan, ésta ya contendrá métodos para las acciones viewAny
, view
, create
, update
, delete
, restore
, y forceDelete
.
Nota
Todas las policies se resuelven a través del contenedor de servicios de Laravel, lo que le permite escribir cualquier dependencia necesaria en el constructor de la policy para que se inyecten automáticamente.
Policies con Respuestas
Hasta ahora, sólo hemos examinado los métodos de policy que devuelven valores booleanos simples. Sin embargo, a veces puede que desee devolver una respuesta más detallada, incluyendo un mensaje de error. Para ello, puede devolver una instancia Illuminate\Auth\Access\Response
desde el método de su policy:
use App\Models\Post;use App\Models\User;use Illuminate\Auth\Access\Response; /** * Determine if the given post can be updated by the user. * * @param \App\Models\User $user * @param \App\Models\Post $post * @return \Illuminate\Auth\Access\Response */public function update(User $user, Post $post){ return $user->id === $post->user_id ? Response::allow() : Response::deny('You do not own this post.');}
Cuando devuelva una respuesta de autorización de su policy, el método Gate::allows
seguirá devolviendo un simple valor booleano; sin embargo, puede utilizar el método Gate::inspect
para obtener la respuesta de autorización completa devuelta por la gate:
use Illuminate\Support\Facades\Gate; $response = Gate::inspect('update', $post); if ($response->allowed()) { // The action is authorized...} else { echo $response->message();}
Cuando se utiliza el método Gate::authorize
, que lanza una AuthorizationException
si la acción no está autorizada, el mensaje de error proporcionado por la respuesta de autorización se propagará a la respuesta HTTP:
Gate::authorize('update', $post); // The action is authorized...
Personalización del estado de la respuesta HTTP
Cuando se deniega una acción a través de un método de policy, se devuelve una respuesta HTTP 403
; sin embargo, a veces puede ser útil devolver un código de estado HTTP alternativo. Puede personalizar el código de estado HTTP devuelto para una comprobación de autorización fallida utilizando el constructor estático denyWithStatus
de la clase Illuminate\Auth\Access\Response
:
use App\Models\Post;use App\Models\User;use Illuminate\Auth\Access\Response; /** * Determine if the given post can be updated by the user. * * @param \App\Models\User $user * @param \App\Models\Post $post * @return \Illuminate\Auth\Access\Response */public function update(User $user, Post $post){ return $user->id === $post->user_id ? Response::allow() : Response::denyWithStatus(404);}
Debido a que ocultar recursos a través de una respuesta 404
es un patrón muy común en las aplicaciones web, el método denyAsNotFound
se ofrece para más comodidad:
use App\Models\Post;use App\Models\User;use Illuminate\Auth\Access\Response; /** * Determine if the given post can be updated by the user. * * @param \App\Models\User $user * @param \App\Models\Post $post * @return \Illuminate\Auth\Access\Response */public function update(User $user, Post $post){ return $user->id === $post->user_id ? Response::allow() : Response::denyAsNotFound();}
Métodos sin modelos
Algunos métodos de policy sólo reciben una instancia del usuario autenticado en ese momento. Esta situación es más común cuando se autorizan acciones de creación
. Por ejemplo, si está creando un blog, puede que desee determinar si un usuario está autorizado a crear alguna entrada. En estas situaciones, el método de su policy sólo debería esperar recibir una instancia de usuario:
/** * Determine if the given user can create posts. * * @param \App\Models\User $user * @return bool */public function create(User $user){ return $user->role == 'writer';}
Usuarios invitados
De forma predeterminada, todas las gates y policies devuelven automáticamente false
si la solicitud HTTP entrante no fue iniciada por un usuario autenticado. Sin embargo, puede permitir que estas comprobaciones de autorización pasen a través de sus gates y policies declarando una sugerencia de tipo "opcional" o proporcionando un valor predeterminado nulo
para la definición del argumento de usuario:
<?php namespace App\Policies; use App\Models\Post;use App\Models\User; class PostPolicy{ /** * Determine if the given post can be updated by the user. * * @param \App\Models\User $user * @param \App\Models\Post $post * @return bool */ public function update(?User $user, Post $post) { return optional($user)->id === $post->user_id; }}
Filtros
Para ciertos usuarios, es posible que desee autorizar todas las acciones dentro de una policy determinada. Para ello, defina un método before
en la policy. El método before
se ejecutará antes que cualquier otro método de la policy, dándole la oportunidad de autorizar la acción antes de que el método de policy sea llamado. Esta función se utiliza normalmente para autorizar a los administradores de aplicaciones a realizar cualquier acción:
use App\Models\User; /** * Perform pre-authorization checks. * * @param \App\Models\User $user * @param string $ability * @return void|bool */public function before(User $user, $ability){ if ($user->isAdministrator()) { return true; }}
Si desea denegar todas las comprobaciones de autorización para un tipo concreto de usuario, puede devolver false
en el método before
. Si se devuelve null
, la comprobación de autorización pasará al método de policy.
Advertencia
El métodobefore
de una clase de policy no será llamado si la clase no contiene un método con un nombre que coincida con el nombre de la acción que se está comprobando.
Autorización de acciones mediante policies
A través del modelo de usuario
El modelo App\Models\User
que se incluye con su aplicación Laravel incluye dos métodos útiles para autorizar acciones: can
y cannot
. Los métodos can
y cannot
reciben el nombre de la acción que deseas autorizar y el modelo relevante. Por ejemplo, vamos a determinar si un usuario está autorizado a actualizar un determinado modelo App\Models\Post
. Típicamente, esto se hará dentro de un método controlador:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Models\Post;use Illuminate\Http\Request; class PostController extends Controller{ /** * Update the given post. * * @param \Illuminate\Http\Request $request * @param \App\Models\Post $post * @return \Illuminate\Http\Response */ public function update(Request $request, Post $post) { if ($request->user()->cannot('update', $post)) { abort(403); } // Update the post... }}
Si hay una policy está registrada para el modelo dado, el método can
llamará automáticamente a la policy apropiada y devolverá el resultado booleano. Si no hay ninguna policy registrada para el modelo, el método can
intentará llamar a la gate que coincida con el nombre de la acción dada.
Acciones que no requieren modelos
Recuerde que algunas acciones pueden corresponder a métodos de policy como create
que no requieren una instancia de modelo. En estas situaciones, puede pasar un nombre de clase al método can
. El nombre de la clase se utilizará para determinar qué policy utilizar al autorizar la acción:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Models\Post;use Illuminate\Http\Request; class PostController extends Controller{ /** * Create a post. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response */ public function store(Request $request) { if ($request->user()->cannot('create', Post::class)) { abort(403); } // Create the post... }}
Autorizacion Mediante Controller Helpers
Además de los métodos de ayuda proporcionados al modelo App\Models\User
, Laravel proporciona un método authorize
a cualquiera de sus controladores que extiendan la clase base App\Http\Controllers\Controller
.
Al igual que el método can
, este método acepta el nombre de la acción que desea autorizar y el modelo correspondiente. Si la acción no está autorizada, el método authorize
lanzará una excepción Illuminate\Auth\Access\AuthorizationException
que el gestor de excepciones de Laravel convertirá automáticamente en una respuesta HTTP con un código de estado 403:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Models\Post;use Illuminate\Http\Request; class PostController extends Controller{ /** * Update the given blog post. * * @param \Illuminate\Http\Request $request * @param \App\Models\Post $post * @return \Illuminate\Http\Response * * @throws \Illuminate\Auth\Access\AuthorizationException */ public function update(Request $request, Post $post) { $this->authorize('update', $post); // The current user can update the blog post... }}
Acciones que no requieren modelos
Como se ha comentado anteriormente, algunos métodos de policy como create
no requieren una instancia de modelo. En estas situaciones, debes pasar un nombre de clase al método authorize
. El nombre de la clase se utilizará para determinar qué policy utilizar al autorizar la acción:
use App\Models\Post;use Illuminate\Http\Request; /** * Create a new blog post. * * @param \Illuminate\Http\Request $request * @return \Illuminate\Http\Response * * @throws \Illuminate\Auth\Access\AuthorizationException */public function create(Request $request){ $this->authorize('create', Post::class); // The current user can create blog posts...}
Autorización de controladores de recursos
Si está utilizando controladores de recursos, puede hacer uso del método authorizeResource
en el constructor de su controlador. Este método adjuntará las definiciones de middleware can
apropiadas a los métodos del controlador de recursos.
El método authorizeResource
acepta el nombre de la clase del modelo como primer argumento, y el nombre del parámetro de ruta/solicitud que contendrá el ID del modelo como segundo argumento. Debes asegurarte de que tu controlador de recursos se crea utilizando el flag --model
para que tenga las definiciones de método y las sugerencias de tipo necesarias:
<?php namespace App\Http\Controllers; use App\Http\Controllers\Controller;use App\Models\Post;use Illuminate\Http\Request; class PostController extends Controller{ /** * Create the controller instance. * * @return void */ public function __construct() { $this->authorizeResource(Post::class, 'post'); }}
Los siguientes métodos de controlador se asignarán a su correspondiente método de policy. Cuando las peticiones se dirijan al método de controlador dado, el método de policy correspondiente se invocará automáticamente antes de que se ejecute el método de controlador:
Método de Controlador | Método de Policy |
---|---|
index | viewAny |
show | view |
create | create |
store | create |
edit | update |
update | update |
destroy | delete |
Nota
Puede utilizar el comandomake:policy
con la opción--model
para generar rápidamente una clase de policy para un modelo dado:php artisan make:policy PostPolicy --model=Post
.
Autorización Mediante Middleware
Laravel incluye un middleware que puede autorizar acciones incluso antes de que la solicitud entrante llegue a tus rutas o controladores. Por defecto, el middleware Illuminate\Auth\Authorize
tiene asignada la clave can
en la clase App\Http\Kernel
. Exploremos un ejemplo de uso del middleware can
para autorizar que un usuario pueda actualizar un post:
use App\Models\Post; Route::put('/post/{post}', function (Post $post) { // The current user may update the post...})->middleware('can:update,post');
En este ejemplo, estamos pasando dos argumentos al middleware can
. El primero es el nombre de la acción que deseamos autorizar y el segundo es el parámetro de ruta que deseamos pasar al método de policy. En este caso, dado que estamos utilizando la vinculación implícita de modelos, se pasará un modelo App\Models\Post
al método de policy. Si el usuario no está autorizado a realizar la acción dada, una respuesta HTTP con un código de estado 403 será devuelta por el middleware.
Por conveniencia, también puede adjuntar el middleware can
a su ruta usando el método can
:
use App\Models\Post; Route::put('/post/{post}', function (Post $post) { // The current user may update the post...})->can('update', 'post');
Acciones que no requieren modelos
De nuevo, algunos métodos de policy como create
no requieren una instancia de modelo. En estas situaciones, puede pasar un nombre de clase al middleware. El nombre de la clase se utilizará para determinar qué policy utilizar al autorizar la acción:
Route::post('/post', function () { // The current user may create posts...})->middleware('can:create,App\Models\Post');
Especificar el nombre completo de la clase dentro de una cadena de definición de middleware puede llegar a ser engorroso. Por esta razón, puede elegir adjuntar middleware middleware can
a su ruta utilizando el método can
:
use App\Models\Post; Route::post('/post', function () { // The current user may create posts...})->can('create', Post::class);
Autorización Mediante plantillas Blade
Al escribir plantillas Blade, puede que desee mostrar una parte de la página sólo si el usuario está autorizado a realizar una acción determinada. Por ejemplo, puede que desee mostrar un formulario de actualización para una entrada de blog sólo si el usuario puede realmente actualizar la entrada. En este caso, puede utilizar las directivas @can
y @cannot
:
@can('update', $post) <!-- The current user can update the post... -->@elsecan('create', App\Models\Post::class) <!-- The current user can create new posts... -->@else <!-- ... -->@endcan @cannot('update', $post) <!-- The current user cannot update the post... -->@elsecannot('create', App\Models\Post::class) <!-- The current user cannot create new posts... -->@endcannot
Estas directivas son atajos prácticos para escribir sentencias @if
y @unless
. Las sentencias @can
y @cannot
anteriores son equivalentes a las siguientes sentencias:
@if (Auth::user()->can('update', $post)) <!-- The current user can update the post... -->@endif @unless (Auth::user()->can('update', $post)) <!-- The current user cannot update the post... -->@endunless
También puede determinar si un usuario está autorizado a realizar cualquier acción de un array dado de acciones. Para ello, utilice la directiva @canany
:
@canany(['update', 'view', 'delete'], $post) <!-- The current user can update, view, or delete the post... -->@elsecanany(['create'], \App\Models\Post::class) <!-- The current user can create a post... -->@endcanany
Acciones que no requieren modelos
Como la mayoría de los otros métodos de autorización, puede pasar un nombre de clase a las directivas @can
y @cannot
si la acción no requiere una instancia de modelo:
@can('create', App\Models\Post::class) <!-- The current user can create posts... -->@endcan @cannot('create', App\Models\Post::class) <!-- The current user can't create posts... -->@endcannot
Suministro de contexto adicional
Al autorizar acciones mediante policies, puede pasar una array como segundo argumento a las distintas funciones y helpers de autorización. El primer elemento del array se utilizará para determinar qué policy debe invocarse, mientras que el resto de los elementos del array se pasan como parámetros al método de policy y pueden utilizarse como contexto adicional al tomar decisiones de autorización. Por ejemplo, considere la siguiente definición del método PostPolicy
que contiene un parámetro adicional $category
:
/** * Determine if the given post can be updated by the user. * * @param \App\Models\User $user * @param \App\Models\Post $post * @param int $category * @return bool */public function update(User $user, Post $post, int $category){ return $user->id === $post->user_id && $user->canUpdateCategory($category);}
Cuando intentamos determinar si el usuario autenticado puede actualizar un post dado, podemos invocar este método de policy así:
/** * Update the given blog post. * * @param \Illuminate\Http\Request $request * @param \App\Models\Post $post * @return \Illuminate\Http\Response * * @throws \Illuminate\Auth\Access\AuthorizationException */public function update(Request $request, Post $post){ $this->authorize('update', [$post, $request->category]); // The current user can update the blog post...}