-
Notifications
You must be signed in to change notification settings - Fork 11.1k
New issue
Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.
By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.
Already on GitHub? Sign in to your account
[5.6] Fix FormRequest class authorization validation priority #24369
[5.6] Fix FormRequest class authorization validation priority #24369
Conversation
Signed-off-by: Bruno Gaspar <brunofgaspar1@gmail.com>
This would be a change in behavior and should target the master branch (next release). This will affect people that uses request data within the authorization callback; they will no longer have the data validated when called, and would need to validate it themselves. |
That's a good point @sisve and thanks for taking the time to look at it. I can be wrong though, but the data doesn't seem to be validated that early (at least that's what i'm seeing on my end), it just calls the |
You're right, I totally misread that code. The authorization is always done before validating the data, this change will just slightly delay calling getValidatorInstance until we know that the authorization succeeded. |
@sisve @taylorotwell @brunogaspar Something like this shouldn't have been pushed into the current branch, this broke a part of my app where i'm storing the user that i'm updating within an attribute of the FormRequest class. |
@shadoWalker89 Please paste your FormRequest class so i can see why it broke for you. This PR actually fixed a logic bug as i mentioned on the OP. |
I'm assigning the property When the order of the methods calls changed it broke my app. class UpdateUserRequest extends FormRequest
{
protected $userBeingUpdated;
public function authorize()
{
return $this->user()->can('users.edit', $this->userBeingUpdated);
}
public function rules()
{
// This being set here and the used in the authorize()
$this->userBeingUpdated = $this->route()->parameter('user');
// My rules over here
}
} |
@shadoWalker89 Thanks for sharing! You could put both of those lines in the same method to prevent breakage. Or even inline it if that is the only place you're using that variable. If you want to use it in multiple places, adding your own getter method could work too so it doesn't depend on the order of the method calls. public function authorize()
{
$this->userBeingUpdated = $this->route()->parameter('user');
return $this->user()->can('users.edit', $this->userBeingUpdated);
}
// or
public function authorize()
{
return $this->user()->can('users.edit', $this->route()->parameter('user'));
} |
@taylorotwell I'm happy there are solutions documented here, but I do think it's still very disruptive to merge a breaking change like this into a minor version. |
I'm usually very paranoid about breaking changes, but not in this case. If I understand it correctly, the rules method was used in this context for something other that it was intended. Not only did it return validation rules, but read route parameters and set flags and thus having side effects. Imagine having a workflow of 1) eating breakfast and 2) go to work. Imagine that you need to put on pants somewhere, and you decide to add that to the breakfast step. This works for you, and pants-and-breakfast becomes a regular maneuver ... until your employer starts a "have breakfast at work"-movement. The proper solution depends on the architecture. Couldn't a simple |
There are also hook methods available in form requests to allow for any extra logic that needs to be run. "validationData()" allows changing any of the data that needs to be validated and "prepareForValidation()" ( provided by the validatesWhenResolved trait), allows running code before validation starts. |
This pull request fixes an issue where the validation rules were being triggered before the authorization, which was leading to issues on some tests i have, where i was not passing some values (on purpose), and the rules were relying on them, however, for that particular test case, i was testing the authorization only and not determining if the provided data was valid.
So now the validation rules only gets triggered if the
authorize()
passes, which seems the proper way.Thanks!