- Intro
- gates
- Crear un gate
- Como un closure
- Como una clase separada
- Usar un gate
- Usar gate para un resource
- Verificar si un user pasa un gate
- Correr logica antes o despues de los gates
- Crear un gate
- Policies
- Escribir policies
- Reglas generales
- Logica previa a las reglas
- Usar policies
- Determinar si un user tiene autorizacion
- Usar policies como Middleware
- Usar policies en controllers
- Escribir policies
Laravel tienedos formas de autorizar acciones
- Gates
- Autorizacion usando closures
- Para cosas simples
- policies
- Autorizacion basada en una clase
- Para cosas compejas
- Puede compartirse entre varias rutas, modelos o recursos
Los gates se definen en la funcion boot() del AuthServiceProvider usando la Gate facade y reciben una instancia del usuario como primer argumento.
Puede recibir otros argumentos, como por ej algun modelo de eloquent
El gate debe devolver un BOOLEAN
public function boot()
{
$this->registerPolicies();
Gate::define('MiGate', function ($user, $post) {
//Devolver un boolean!
return $user->id == $post->user_id;
});
}
Podes definir tu gate en una clase separada y despues acceder a sus metodos igual que como haces con un controller. es mucho mas limpio
En tu clase separada
namespare App/misClases/MiGate
class MiPostGate{
function actualizar($user, $post){
//hacer cosas
}
function crear($user, $post){
//hacer cosas
}
}
En AuthServiceProvider
public function boot()
{
$this->registerPolicies();
Gate::define('actualizar-post', MiPostGate@actualizar);
Gate::define('crear-post', MiPostGate@crear);
}
Una vez que creaste un gate, para usar un gate para decidir algo cuando un usuario esta loguead:
// Si el gate devuelve true
if (Gate::allows('MiGate', $post)) {
// The current user can update the post...
}
// Si el gate devuelve false
if (Gate::denies('MiGate', $post)) {
// The current user can't update the post...
}
laravel pasa la instancia de este usuario al gate automaticamente
Podes abreviar con una sola linea todos los gates para las operaciones CRUD
Gate::resource('posts', 'App\Policies\PostPolicy');
Equivale a:
Gate::define('posts.view', 'App\Policies\PostPolicy@view');
Gate::define('posts.create', 'App\Policies\PostPolicy@create');
Gate::define('posts.update', 'App\Policies\PostPolicy@update');
Gate::define('posts.delete', 'App\Policies\PostPolicy@delete');
Si tenes un model de un usuario y queres ver si pasa un gate, haces:
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...
}
Podes correr una pieza de codigo antes de que se corra cualquier gate usando la funcion gate::before()
Si la funcion devuelve algo que no es NULL entonces se considera a ese valor el resultado de los gates
Gate::before(function ($user, $ability) {
if ($user->isSuperAdmin()) {
//Los gates no se corren, esta sera la respuesta del gate
return true;
} else{
//Los gates que vienen despues se corren normalmente
return null
}
});
Correr algo despues de los gates:
Gate::after(function ($user, $ability, $result, $arguments) {
//
});
Son clases que organizan la logica de autorizacion alrededor de un modelo o recurso. Por lo que estan necesariamente atadas a un model
Se guardan en app/Policies
- Para crearlos:
- Un policy generico
php artisan make:policy MiPolicy
- Un policy con metodos CRUD armados
php artisan make:policy PostPolicy --model=Post
- Un policy generico
.
-
Se registran en el AuthServiceProvider asi: como un policy esta atado a un model necesariamente, hay que registrar el policy junto con el model.
//En el AuthServiceProvider protected $policies = [ MiModelo::class => MiModeloPolicy::class, ];
-
Se ven asi:
namespace App\Policies; use App\User; use App\Post; class PostPolicy { public function editarElPost(User $user, Post $post) { return $user->id === $post->user_id; } }
-
Se usan asi:
if ($user->can('editarElPost', $post)) { // }
Las policies estan constituidas por
- Metodos que describen que es lo que se esta autorizando
- Reciben como parametros:
- Al user
- Una instancia particular del modelo (opcional)
- Devuelven
- True si se autoriza la accion a ese user en ese modelo
- false si no.
- Reciben como parametros:
Las funciones deben devolver true o false dependiendo de si la accion fue autorizada o no.
class PostPolicy
{
//El usuario puede ACTUALIZAR este post?
public function actualizar(User $user, Post $post)
{
//Si el user creo este post, entonces si
return $user->id === $post->user_id;
}
//El usuario puede CREAR este post?
public function CREAR(User $user)
{
// si una columna en la DB llamada "puedePostear" es true
return $user->puedePostear === true;
}
}
Podes tener logia antes de que se ejecute cualquiera de las funciones de la policy con la funcion before().
// El usuario y la habilidad solicitada son parametros
public function before($user, $ability)
{
//Si el user es admin, autorizar todo y no correr ninguna regla
if ($user->isSuperAdmin()) {
return true;
}
}
podes usar el helper function del modelo user, que pide el nombre del metodo del policy y el nombre del modelo a modificar.
como hay un solo policy por modelo, laravel sabe cual es el policy de $post solamente sabiendo su modelo.
//Editar un modelo
if ($user->can('actualizar', $post)) {
// ejecuta ACTUALIZAR() en el policy
}
//Crear una instancia de un modelo
if ($user->can('create', Post::class)) {
// ejecuta "CREAR()" en el policy
}
Podes hacer uso del Middleware Illuminate\Auth\Middleware\Authorize para determinar si un usuario puede hacer algo indicando:
- can o cant
- La funcion del policy que quier correr
- Un route parameter que enviar a la funcion (generalmente un ID)
- El nombre del modelo que queres crear
Para editar un modelo:
Route::put('/post/{miParametro}', MiController@update)
->middleware('can:ACTUALIZAR,miParametro');
Para crear un modelo:
Route::post('/post',MiController@create)
->middleware('can:CREAR,App\Post');
Dentro del controller podes usar el metodo authorize() para determiar si una accion tiene el permiso necesario.
Tiene como parametros:
- El nombre de la funcion del policy
- La instancia del Modelo para editar modelos
- La clase del modelo para crear modelos
Concecuencias:
- Si autoriza: el codigo continua normalmente
- Si no autoriza:
- Se genera una aurhotization exception
- Se devuelve un HTTP code 403
//Editar modelos
public function update(Request $request, Post $post)
{
$this->authorize('ACTUALIZAR', $post);
// Hacer el update!
}
//crear modelos
public function create(Request $request)
{
$this->authorize('CREAR', Post::class);
// Crear el elemento!
}