Policy son clases que resuelven los permisos para un objeto determinado. Puede crear una policy para cualquier clase de su aplicación a la que desee aplicar comprobaciones de permisos.
Puede crear una policy en su directorio src/Policy
. Las clases policy
no tienen una clase o interfaz base común que se espera implementar.
Las clases de la aplicación se “resuelven” en una clase policy coincidente.
Consulte la sección policy-resolvers para saber cómo se pueden resolver las policy.
Por lo general, querrá poner sus policy en src/Policy y usar el sufijo de clase
Policy
. Por ahora crearemos una clase policy para la entidad Article en nuestra
aplicación. En src/Policy/ArticlePolicy.php ponga el siguiente contenido:
<?php
namespace App\Policy;
use App\Model\Entity\Article;
use Authorization\IdentityInterface;
class ArticlePolicy
{
}
Además de las entidades, los objetos table y query pueden tener una policy.
Los objetos query tendrán su método llamado repository()
, y se generará una clase
policy basada en el nombre de la “table”. Una clase “table” de App\Model\Table\ArticlesTable
se mapeará a App\Policy\ArticlesTablePolicy
.
Puede generar clases policy vacías para objetos ORM usando bake
:
# Create an entity policy
bin/cake bake policy --type entity Article
# Create a table policy
bin/cake bake policy --type table Articles
La clase policy que acabamos de crear no hace mucho en este momento. Definamos un método que nos permita comprobar si un usuario puede actualizar un artículo:
public function canUpdate(IdentityInterface $user, Article $article)
{
return $user->id == $article->user_id;
}
Los métodos policy deben devolver objetos true
o un objeto Result
para indicar el éxito (“pass”).
Todos los demás valores se interpretarán como un fallo (“fail”).
Los métodos policy recibirán un null
en el parámetro $user
al manejar usuarios
no autenticados. Si desea que los métodos policy automáticamente den “fail” para usuarios
anónimos, puede usar la sugerencia de tipo IdentityInterface
.
Además de los valores booleanos, los métodos policy pueden devolver un objeto Result
.
Los objetos Result
permiten que se proporcione más contexto sobre por qué el método
policy dió “pass”/”fail”:
use Authorization\Policy\Result;
public function canUpdate(IdentityInterface $user, Article $article)
{
if ($user->id == $article->user_id) {
return new Result(true);
}
// Results let you define a 'reason' for the failure.
return new Result(false, 'not-owner');
}
Cualquier valor devuelto que no sea true
o un objeto ResultInterface
se considerará un “fail”.
Además de que las policy pueden definir verificaciones de autorización “pass”/”fail”, también pueden definir “alcances”. Los métodos de alcance le permiten modificar otro objeto aplicando condiciones de autorización. Un caso de uso perfecto para esto es restringir una list view al usuario actual:
namespace App\Policy;
class ArticlesTablePolicy
{
public function scopeIndex($user, $query)
{
return $query->where(['Articles.user_id' => $user->getIdentifier()]);
}
}
En algunas policy, es posible que desee aplicar comprobaciones comunes en todas las
operaciones de una policy. Esto es útil cuando necesita denegar todas las acciones al
recurso proporcionado. Para utilizar las condiciones previas, debe implementar BeforePolicyInterface
en su policy:
namespace App\Policy;
use Authorization\IdentityInterface;
use Authorization\Policy\BeforePolicyInterface;
use Authorization\Policy\ResultInterface;
class ArticlesPolicy implements BeforePolicyInterface
{
public function before(?IdentityInterface $identity, mixed $resource, string $action): ResultInterface|bool|null
{
if ($identity->getOriginalData()->is_admin) {
return true;
}
// fall through
}
}
De los hooks “before” se espera que devuelvan uno de tres valores:
true
El usuario puede proceder con la acción.
false
El usuario no puede proceder con la acción.
null
El hook “before” no tomó una decisión y se invocará
el método de autorización.