J'implémente une API dans Laravel en utilisant la spécification JSON: API.
Je contient une ressource, appelons-la Ponds, avec des relations plusieurs-à-plusieurs avec une autre ressource, appelons-la Ducks.
Selon JSON: spécifications API afin de supprimer une telle relation je devrais utiliser DELETE / ponds / {id} / relations / ducks endpoint, avec la demande du corps suivant:
{
"data": [
{ "type": "ducks", "id": "123" },
{ "type": "ducks" }
]
}
Ceci est géré par PondRemoveDucksRequest, qui ressemble à ceci:
<?php
...
class PondRemoveDucksRequest extends FormRequest
{
public function authorize()
{
return $this->allDucksAreRemovableByUser();
}
public function rules()
{
return [
"data.*.type" => "required|in:ducks",
"data.*.id" => "required|string|min:1"
];
}
protected function allDucksAreRemovableByUser(): bool
{
// Here goes the somewhat complex logic determining if the user is authorized
// to remove each and every relationship passed in the data array.
}
}
Le problème est que si j'envoie un corps tel que:
{
"data": [
{ "type": "ducks", "id": "123" },
{ "type": "ducks", "id": "987" }
]
}
, j'obtiens a 500, car le contrôle d'autorisation est déclenché en premier et repose sur la présence d'identifiants dans chaque élément du tableau. Idéalement, j'aimerais obtenir une erreur 422 avec un message standard de la validation des règles.
La solution rapide que je vois est d'ajouter la vérification de présence d'identifiant dans la méthode allDucksAreRemovableByUser (), mais cela semble quelque peu piraté.
Existe-t-il un meilleur moyen de vérifier d'abord les règles de validation, puis de passer à la partie autorisation?
Merci d'avance!
3 Réponses :
Voici une approche légèrement différente de celle que vous essayez, mais elle peut accomplir le résultat souhaité pour vous.
Si vous essayez de valider si l'ID de canard donné appartient à l'utilisateur, cela peut être fait dans le se règle comme suit:
"data.*.id" => "bail|required|string|min:1|exists:ducks,id,user_id,".Auth::user()->id
Cette règle demande s'il existe un enregistrement dans la table ducks qui correspond à l'id et où l'ID_utilisateur est l'ID_utilisateur actuellement connecté.
Si vous l'enchaînez à vos règles existantes (obligatoire | string | min: 1), en utilisant 'bail', alors il n'exécutera pas la requête à moins d'avoir d'abord passé les trois autres règles: p>
"data.*.id" => "exists:ducks,id,user_id,".Auth::user()->id
Cela ressemble à une solution valable au cas où la logique d'autorisation ne repose que sur la relation entre l'utilisateur et l'étang. Malheureusement dans mon cas, il y a plus - il faut déterminer les choses en ce qui concerne les préférences de l'utilisateur, la relation avec l'entité mère de l'étang (je ne peux pas trouver une belle analogie pour le moment;)) etc. Merci quand même, je pense que cela peut être utile dans de nombreux autres cas.
ajoutez $ this-> get Validator Instance () -> validate (); au début de la méthode authorize ()
1 - Créez une classe abstraite appelée "FormRequest" dans le répertoire App \ Requests et remplacez le Méthode validateResolved ():
<?php
namespace App\Http\Requests\Orders;
use App\Http\Requests\FormRequest;
class StoreOrderRequest extends FormRequest
{
}
2 - Étendez vos FormRequests avec FormRequest personnalisé
<?php
namespace App\Http\Requests;
use Illuminate\Validation\ValidationException;
use Illuminate\Auth\Access\AuthorizationException;
use Illuminate\Foundation\Http\FormRequest as BaseFormRequest;
abstract class FormRequest extends BaseFormRequest
{
/**
* Validate the class instance.
*
* @return void
* @throws AuthorizationException
* @throws ValidationException
*/
public function validateResolved()
{
$validator = $this->getValidatorInstance();
if ($validator->fails())
{
$this->failedValidation($validator);
}
if (!$this->passesAuthorization())
{
$this->failedAuthorization();
}
}
}
Pourriez-vous poster où vous appelez les règles de validation s'il vous plaît?
@ party-ring Je ne sais pas si j'ai compris votre question. Pour autant que je sache, les règles de validation sont vérifiées automatiquement lorsque la requête est utilisée dans les paramètres de la méthode du contrôleur.
Dans votre contrôleur lorsque vous récupérez la requête, pourriez-vous dd
$ request-> validated ();juste pour voir si la requête passe la validation? Parce que s'il réussit, il y a un problème avec la validation, et si cela échoue, vous devez rejeter cette demande :)@ party-ring La validation des règles elle-même semble fonctionner, puisqu'elle renvoie 422 si un "type" incorrect est fourni dans l'un des éléments supprimés. Je vérifierai si l'ajout de $ request-> validated (); aide avec l'ordre des règles par rapport aux contrôles d'autorisation, merci!
une chance pour le résoudre?
@ party-ring L'ajout de l'appel
$ request-> validated ()dans le contrôleur n'a fait aucune différence. Je suppose que la logique d'autorisation de FormRequest est exécutée avant tout code dans les méthodes du contrôleur. Ce qui a aidé a été d'ajouter$ this-> getValidatorInstance () -> validated ();au début de la méthodeauthorize ().getValidatorInstance ()est requis, car lorsque la logique d'autorisation est exécutée, le validateur n'est pas encore instancié. De cette façon, j'ai reçu des messages d'erreur standard et une validation basée sur lesrègles (). Cela semble toujours un peu désordonné, je pense à le déplacer vers un middleware.La validation par l'OMI avant l'autorisation semble erronée. Le renvoi d'erreurs de validation à un utilisateur qui n'est pas du tout autorisé à voir cette ressource peut entraîner la divulgation d'informations. Je recommanderais de garder dans votre logique d'autorisation contre les demandes mal formées.