#Introducción
Además de proporcionar servicios integrados de autenticación, Laravel también ofrece una forma sencilla de autorizar acciones de usuario sobre un recurso dado. Por ejemplo, aunque un usuario esté autenticado, puede que no esté autorizado para actualizar o eliminar ciertos modelos Eloquent o registros de base de datos gestionados por su aplicación. Las características de autorización de Laravel proporcionan una manera fácil y organizada de gestionar este tipo de comprobaciones de autorización.
Laravel ofrece dos formas principales de autorizar acciones: gates y policies. Puede pensar en gates y policies como rutas y controladores. Los gates proporcionan un enfoque simple basado en closures para la autorización, mientras que las policies, como los controladores, agrupan la lógica alrededor de un modelo o recurso particular. En esta documentación, primero exploraremos los gates y luego examinaremos las policies.
No es necesario elegir entre usar exclusivamente gates o exclusivamente policies al construir una aplicación. La mayoría de las aplicaciones probablemente contendrán una mezcla de gates y policies, ¡y eso está perfectamente bien! Los gates son más aplicables a acciones que no están relacionadas con ningún modelo o recurso, como ver un panel de administrador. En contraste, las policies deben usarse cuando se desea autorizar una acción para un modelo o recurso particular.
#Gates
#Escribiendo Gates
Los gates son una excelente manera de aprender los conceptos básicos de las características de autorización de Laravel; sin embargo, al construir aplicaciones robustas de Laravel debería considerar usar policies para organizar sus reglas de autorización.
Los gates son simplemente closures que determinan si un usuario está autorizado para realizar una acción dada. Normalmente, los gates se definen dentro del método boot de la clase App\Providers\AuthServiceProvider usando la fachada Gate. Los gates siempre reciben una instancia de usuario como primer argumento y opcionalmente pueden recibir argumentos adicionales como un modelo Eloquent relevante.
En este ejemplo, definiremos un gate para determinar si un usuario puede actualizar un modelo App\Models\Post dado. El gate lo hará 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;
/**
* Registrar cualquier servicio de autenticación / autorización.
*/
public function boot(): void
{
Gate::define('update-post', function (User $user, Post $post) {
return $user->id === $post->user_id;
});
}
Al igual que los controladores, los gates también pueden definirse usando un callback de clase en forma de array:
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
/**
* Registrar cualquier servicio de autenticación / autorización.
*/
public function boot(): void
{
Gate::define('update-post', [PostPolicy::class, 'update']);
}
#Autorizando Acciones
Para autorizar una acción usando gates, debe usar los métodos allows o denies proporcionados por la fachada Gate. Tenga en cuenta que no es necesario pasar el usuario autenticado actualmente a estos métodos. Laravel se encargará automáticamente de pasar el usuario al closure del gate. Es común llamar a los métodos de autorización del gate dentro de los controladores de su 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\RedirectResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class PostController extends Controller
{
/**
* Actualizar el post dado.
*/
public function update(Request $request, Post $post): RedirectResponse
{
if (! Gate::allows('update-post', $post)) {
abort(403);
}
// Actualizar el post...
return redirect('/posts');
}
}
Si desea determinar si un usuario distinto al actualmente autenticado está autorizado para realizar una acción, puede usar el método forUser en la fachada Gate:
if (Gate::forUser($user)->allows('update-post', $post)) {
// El usuario puede actualizar el post...
}
if (Gate::forUser($user)->denies('update-post', $post)) {
// El usuario no puede actualizar el post...
}
Puede autorizar múltiples acciones a la vez usando los métodos any o none:
if (Gate::any(['update-post', 'delete-post'], $post)) {
// El usuario puede actualizar o eliminar el post...
}
if (Gate::none(['update-post', 'delete-post'], $post)) {
// El usuario no puede actualizar ni eliminar el post...
}
#Autorizar o Lanzar Excepciones
Si desea intentar autorizar una acción y lanzar automáticamente una excepción Illuminate\Auth\Access\AuthorizationException si el usuario no está autorizado para realizar la acción dada, puede usar el método authorize de la fachada Gate. Las instancias de AuthorizationException son automáticamente convertidas en una respuesta HTTP 403 por el manejador de excepciones de Laravel:
Gate::authorize('update-post', $post);
// La acción está autorizada...
#Proporcionando Contexto Adicional
Los métodos de 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. Estos elementos del array se pasan como parámetros al closure del gate y pueden usarse para 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, bool $pinned) {
if (! $user->canPublishToGroup($category->group)) {
return false;
} elseif ($pinned && ! $user->canPinPosts()) {
return false;
}
return true;
});
if (Gate::check('create-post', [$category, $pinned])) {
// El usuario puede crear el post...
}
#Respuestas de Gates
Hasta ahora, solo hemos examinado gates que retornan valores booleanos simples. Sin embargo, a veces puede desear devolver una respuesta más detallada, incluyendo un mensaje de error. Para ello, puede devolver una instancia de 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('Debe ser administrador.');
});
Incluso cuando devuelve una respuesta de autorización desde su gate, el método Gate::allows seguirá devolviendo un valor booleano simple; sin embargo, puede usar el método Gate::inspect para obtener la respuesta completa de autorización devuelta por el gate:
$response = Gate::inspect('edit-settings');
if ($response->allowed()) {
// La acción está autorizada...
} else {
echo $response->message();
}
Al usar 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('edit-settings');
// La acción está autorizada...
#Personalizando el Estado HTTP de la Respuesta
Cuando una acción es denegada vía un 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 para una comprobación de autorización fallida usando 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);
});
Debido a que ocultar recursos mediante una respuesta 404 es un patrón común en aplicaciones web, se ofrece el método denyAsNotFound para mayor 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();
});
#Interceptando Comprobaciones de Gates
A veces, puede que desee conceder todas las habilidades a un usuario específico. Puede usar el método before para definir un closure que se ejecuta antes de todas las demás comprobaciones de autorización:
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::before(function (User $user, string $ability) {
if ($user->isAdministrator()) {
return true;
}
});
Si el closure before devuelve un resultado no nulo, ese resultado será considerado como el resultado de la comprobación de autorización.
Puede usar el método after para definir un closure que se ejecuta después de todas las demás comprobaciones de autorización:
use App\Models\User;
Gate::after(function (User $user, string $ability, bool|null $result, mixed $arguments) {
if ($user->isAdministrator()) {
return true;
}
});
Al igual que el método before, si el closure after devuelve un resultado no nulo, ese resultado será considerado como el resultado de la comprobación de autorización.
#Autorización Inline
Ocasionalmente, puede que desee determinar si el usuario autenticado actualmente está autorizado para realizar una acción dada sin escribir un gate dedicado que corresponda a la acción. Laravel le permite realizar este tipo de comprobaciones de autorización "inline" mediante los métodos Gate::allowIf y Gate::denyIf. La autorización inline no ejecuta ningún "hook" de autorización "before" o "after" definido:
use App\Models\User;
use Illuminate\Support\Facades\Gate;
Gate::allowIf(fn (User $user) => $user->isAdministrator());
Gate::denyIf(fn (User $user) => $user->banned());
Si la acción no está autorizada o si no hay ningún usuario autenticado actualmente, Laravel lanzará automáticamente una excepción Illuminate\Auth\Access\AuthorizationException. Las instancias de AuthorizationException son automáticamente convertidas en una respuesta HTTP 403 por el manejador de excepciones de Laravel.
#Creando Policies
#Generando Policies
Las policies son clases que organizan la lógica de autorización alrededor de un modelo o recurso 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 usando el comando Artisan make:policy. La policy generada se colocará en el directorio app/Policies. Si este directorio no existe en su aplicación, Laravel lo creará por usted:
php artisan make:policy PostPolicy
El comando make:policy generará una clase de policy vacía. Si desea generar una clase con métodos de policy de ejemplo relacionados con ver, crear, actualizar y eliminar el recurso, puede proporcionar la opción --model al ejecutar el comando:
php artisan make:policy PostPolicy --model=Post
#Registrando Policies
Una vez creada la clase de policy, debe registrarse. Registrar policies es cómo informamos a Laravel qué policy usar al autorizar acciones contra un tipo de modelo dado.
El App\Providers\AuthServiceProvider incluido con las aplicaciones Laravel nuevas contiene una propiedad policies que mapea sus modelos Eloquent a sus policies correspondientes. Registrar una policy indicará a Laravel qué policy utilizar al autorizar 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
{
/**
* Los mapeos de policies para la aplicación.
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class,
];
/**
* Registrar cualquier servicio de autenticación / autorización de la aplicación.
*/
public function boot(): void
{
// ...
}
}
#Descubrimiento Automático de Policies
En lugar de registrar manualmente las policies de modelos, Laravel puede descubrir automáticamente las policies siempre que el modelo y la policy sigan las convenciones estándar de nombres de Laravel. Específicamente, las policies deben estar en un directorio Policies en o por encima del directorio que contiene sus modelos. Por ejemplo, los modelos pueden estar en el directorio app/Models mientras que las policies pueden estar en app/Policies. En esta situación, Laravel buscará policies en app/Models/Policies y luego en app/Policies. Además, el nombre de la policy debe coincidir con el nombre del modelo y tener un sufijo Policy. Por ejemplo, un modelo User correspondería a una clase de policy UserPolicy.
Si desea definir su propia lógica de descubrimiento de policies, puede registrar un callback personalizado usando el método Gate::guessPolicyNamesUsing. Normalmente, este método debe llamarse desde el método boot del AuthServiceProvider de su aplicación:
use Illuminate\Support\Facades\Gate;
Gate::guessPolicyNamesUsing(function (string $modelClass) {
// Retornar el nombre de la clase de policy para el modelo dado...
});
Cualquier policy que esté explícitamente mapeada en su AuthServiceProvider tendrá prioridad sobre cualquier policy que pueda ser descubierta automáticamente.
#Escribiendo Policies
#Métodos de Policy
Una vez que la clase de policy ha sido registrada, puede agregar métodos para cada acción que autorice. Por ejemplo, definamos un método update en nuestra PostPolicy que determine si un App\Models\User dado puede actualizar una instancia App\Models\Post dada.
El método update recibirá una instancia de User y una de Post como argumentos, y debe devolver true o false indicando si el usuario está autorizado para actualizar el Post dado. Así, en este ejemplo, verificaremos que el id del usuario coincida con el user_id del post:
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
/**
* Determinar si el post dado puede ser actualizado por el usuario.
*/
public function update(User $user, Post $post): bool
{
return $user->id === $post->user_id;
}
}
Puede continuar definiendo métodos adicionales en la policy según sea necesario para las diversas acciones que autorice. Por ejemplo, podría definir métodos view o delete para autorizar varias acciones relacionadas con Post, pero recuerde que es libre de dar a sus métodos de policy cualquier nombre que desee.
Si usó la opción --model al generar su policy vía la consola Artisan, esta ya contendrá métodos para las acciones viewAny, view, create, update, delete, restore y forceDelete.
Todas las policies se resuelven a través del contenedor de servicios de Laravel, lo que le permite inyectar automáticamente cualquier dependencia necesaria en el constructor de la policy mediante type-hinting.
#Respuestas de Policy
Hasta ahora, solo hemos examinado métodos de policy que devuelven valores booleanos simples. Sin embargo, a veces puede desear devolver una respuesta más detallada, incluyendo un mensaje de error. Para ello, puede devolver una instancia de Illuminate\Auth\Access\Response desde su método de policy:
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
/**
* Determinar si el post dado puede ser actualizado por el usuario.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('No es propietario de este post.');
}
Al devolver una respuesta de autorización desde su policy, el método Gate::allows seguirá devolviendo un valor booleano simple; sin embargo, puede usar el método Gate::inspect para obtener la respuesta completa de autorización devuelta por el gate:
use Illuminate\Support\Facades\Gate;
$response = Gate::inspect('update', $post);
if ($response->allowed()) {
// La acción está autorizada...
} else {
echo $response->message();
}
Al usar 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);
// La acción está autorizada...
#Personalizando el Estado HTTP de la Respuesta
Cuando una acción es denegada vía 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 usando el constructor estático denyWithStatus en la clase Illuminate\Auth\Access\Response:
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
/**
* Determinar si el post dado puede ser actualizado por el usuario.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::denyWithStatus(404);
}
Debido a que ocultar recursos mediante una respuesta 404 es un patrón común en aplicaciones web, se ofrece el método denyAsNotFound para mayor comodidad:
use App\Models\Post;
use App\Models\User;
use Illuminate\Auth\Access\Response;
/**
* Determinar si el post dado puede ser actualizado por el usuario.
*/
public function update(User $user, Post $post): Response
{
return $user->id === $post->user_id
? Response::allow()
: Response::denyAsNotFound();
}
#Métodos Sin Modelos
Algunos métodos de policy solo reciben una instancia del usuario autenticado actualmente. Esta situación es más común al autorizar acciones create. Por ejemplo, si está creando un blog, puede que desee determinar si un usuario está autorizado para crear posts en general. En estas situaciones, su método de policy solo debe esperar recibir una instancia de usuario:
/**
* Determinar si el usuario dado puede crear posts.
*/
public function create(User $user): bool
{
return $user->role == 'writer';
}
#Usuarios Invitados
Por defecto, todos los 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 sus gates y policies declarando un type-hint "opcional" o proporcionando un valor por defecto null para la definición del argumento de usuario:
<?php
namespace App\Policies;
use App\Models\Post;
use App\Models\User;
class PostPolicy
{
/**
* Determinar si el post dado puede ser actualizado por el usuario.
*/
public function update(?User $user, Post $post): bool
{
return $user?->id === $post->user_id;
}
}
#Filtros de Policy
Para ciertos usuarios, puede que desee autorizar todas las acciones dentro de una policy dada. Para lograr esto, defina un método before en la policy. El método before se ejecutará antes que cualquier otro método en la policy, dándole la oportunidad de autorizar la acción antes de que se llame al método de policy previsto. Esta característica se usa comúnmente para autorizar a los administradores de la aplicación a realizar cualquier acción:
use App\Models\User;
/**
* Realizar comprobaciones previas de autorización.
*/
public function before(User $user, string $ability): bool|null
{
if ($user->isAdministrator()) {
return true;
}
return null;
}
Si desea denegar todas las comprobaciones de autorización para un tipo particular de usuario, puede devolver false desde el método before. Si se devuelve null, la comprobación de autorización continuará con el método de policy.
El método before 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 habilidad que se está comprobando.
#Autorizando Acciones Usando Policies
#A través del Modelo User
El modelo App\Models\User incluido 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 desea autorizar y el modelo relevante. Por ejemplo, determinemos si un usuario está autorizado para actualizar un modelo App\Models\Post dado. Normalmente, esto se hará dentro de un método de controlador:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Actualizar el post dado.
*/
public function update(Request $request, Post $post): RedirectResponse
{
if ($request->user()->cannot('update', $post)) {
abort(403);
}
// Actualizar el post...
return redirect('/posts');
}
}
Si se registra una policy para el modelo dado, el método can llamará automáticamente a la policy apropiada y devolverá el resultado booleano. Si no se registra ninguna policy para el modelo, el método can intentará llamar al Gate basado en closure que coincida con el nombre de la acción dada.
#Acciones Que No Requieren Modelos
Recuerde, 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 clase se usará para determinar qué policy usar al autorizar la acción:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Crear un post.
*/
public function store(Request $request): RedirectResponse
{
if ($request->user()->cannot('create', Post::class)) {
abort(403);
}
// Crear el post...
return redirect('/posts');
}
}
#A través de Helpers en Controladores
Además de los métodos útiles proporcionados al modelo App\Models\User, Laravel ofrece un método authorize útil para 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 relevante. Si la acción no está autorizada, el método authorize lanzará una excepción Illuminate\Auth\Access\AuthorizationException que el manejador de excepciones de Laravel convertirá automáticamente en una respuesta HTTP con código de estado 403:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
class PostController extends Controller
{
/**
* Actualizar el post del blog dado.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post): RedirectResponse
{
$this->authorize('update', $post);
// El usuario actual puede actualizar el post del blog...
return redirect('/posts');
}
}
#Acciones Que No Requieren Modelos
Como se discutió anteriormente, algunos métodos de policy como create no requieren una instancia de modelo. En estas situaciones, debe pasar un nombre de clase al método authorize. El nombre de clase se usará para determinar qué policy usar al autorizar la acción:
use App\Models\Post;
use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;
/**
* Crear un nuevo post del blog.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function create(Request $request): RedirectResponse
{
$this->authorize('create', Post::class);
// El usuario actual puede crear posts del blog...
return redirect('/posts');
}
#Autorizando Controladores de Recursos
Si está utilizando controladores de recursos, puede usar el 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 clase del modelo como primer argumento, y el nombre del parámetro de ruta / solicitud que contendrá el ID del modelo como segundo argumento. Debe asegurarse de que su controlador de recursos se haya creado usando la bandera --model para que tenga las firmas de método y type-hints requeridos:
<?php
namespace App\Http\Controllers;
use App\Http\Controllers\Controller;
use App\Models\Post;
class PostController extends Controller
{
/**
* Crear la instancia del controlador.
*/
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
}
Los siguientes métodos del controlador se mapearán a su método de policy correspondiente. Cuando las solicitudes se enruten al método del controlador dado, el método de policy correspondiente se invocará automáticamente antes de que se ejecute el método del controlador:
| Método del Controlador | Método de Policy |
|---|---|
| index | viewAny |
| show | view |
| create | create |
| store | create |
| edit | update |
| update | update |
| destroy | delete |
Puede usar el comando make: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.
#A través de Middleware
Laravel incluye un middleware que puede autorizar acciones antes de que la solicitud entrante siquiera llegue a sus rutas o controladores. Por defecto, el middleware Illuminate\Auth\Middleware\Authorize está asignado a la clave can en su clase App\Http\Kernel. Veamos 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) {
// El usuario actual puede actualizar el 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 usamos binding implícito de modelos, un modelo App\Models\Post será pasado al método de policy. Si el usuario no está autorizado para realizar la acción dada, el middleware devolverá una respuesta HTTP con código de estado 403.
Para mayor comodidad, 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) {
// El usuario actual puede actualizar el post...
})->can('update', 'post');
#Acciones Que No Requieren Modelos
Nuevamente, 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 clase se usará para determinar qué policy usar al autorizar la acción:
Route::post('/post', function () {
// El usuario actual puede crear posts...
})->middleware('can:create,App\Models\Post');
Especificar el nombre completo de la clase dentro de una definición de middleware en cadena puede volverse engorroso. Por esa razón, puede optar por adjuntar el middleware can a su ruta usando el método can:
use App\Models\Post;
Route::post('/post', function () {
// El usuario actual puede crear posts...
})->can('create', Post::class);
#A través de Plantillas Blade
Al escribir plantillas Blade, puede que desee mostrar una parte de la página solo si el usuario está autorizado para realizar una acción determinada. Por ejemplo, puede que desee mostrar un formulario de actualización para una entrada del blog solo si el usuario realmente puede actualizar la entrada. En esta situación, puede utilizar las directivas @can y @cannot:
@can('update', $post)
<!-- El usuario actual puede actualizar el post... -->
@elsecan('create', App\Models\Post::class)
<!-- El usuario actual puede crear nuevos posts... -->
@else
<!-- ... -->
@endcan
@cannot('update', $post)
<!-- El usuario actual no puede actualizar el post... -->
@elsecannot('create', App\Models\Post::class)
<!-- El usuario actual no puede crear nuevos posts... -->
@endcannot
Estas directivas son atajos convenientes para escribir sentencias @if y @unless. Las sentencias @can y @cannot anteriores son equivalentes a las siguientes sentencias:
@if (Auth::user()->can('update', $post))
<!-- El usuario actual puede actualizar el post... -->
@endif
@unless (Auth::user()->can('update', $post))
<!-- El usuario actual no puede actualizar el post... -->
@endunless
También puede determinar si un usuario está autorizado para realizar alguna acción de un array dado de acciones. Para lograr esto, use la directiva @canany:
@canany(['update', 'view', 'delete'], $post)
<!-- El usuario actual puede actualizar, ver o eliminar el post... -->
@elsecanany(['create'], \App\Models\Post::class)
<!-- El usuario actual puede crear un post... -->
@endcanany
#Acciones Que No Requieren Modelos
Al igual que 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)
<!-- El usuario actual puede crear posts... -->
@endcan
@cannot('create', App\Models\Post::class)
<!-- El usuario actual no puede crear posts... -->
@endcannot
#Proporcionando Contexto Adicional
Al autorizar acciones usando policies, puede pasar un array como segundo argumento a las diversas funciones y helpers de autorización. El primer elemento del array se usará 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 usarse para contexto adicional al tomar decisiones de autorización. Por ejemplo, considere la siguiente definición de método PostPolicy que contiene un parámetro adicional $category:
/**
* Determinar si el post dado puede ser actualizado por el usuario.
*/
public function update(User $user, Post $post, int $category): bool
{
return $user->id === $post->user_id &&
$user->canUpdateCategory($category);
}
Al intentar determinar si el usuario autenticado puede actualizar un post dado, podemos invocar este método de policy así:
/**
* Actualizar el post del blog dado.
*
* @throws \Illuminate\Auth\Access\AuthorizationException
*/
public function update(Request $request, Post $post): RedirectResponse
{
$this->authorize('update', [$post, $request->category]);
// El usuario actual puede actualizar el post del blog...
return redirect('/posts');
}