In my Laravel application, I have several policies working, but one will not work.
Controller
public function store(Project $project, CreateActionRequest $request)
{
$this->authorize('store', $project);
Action::create([
'name' => $request->name,
]);
return redirect()->route('projects.show', $project->id)->withSuccess('Massnahme erfolgreich gespeichert');
}
Policy
namespace App\Policies\Project;
use App\Models\Project\Project;
use App\Models\User;
use App\Models\Project\Action;
use Illuminate\Auth\Access\HandlesAuthorization;
class ActionPolicy
{
use HandlesAuthorization;
public function store(User $user, Project $project)
{
return $user->company_id === $project->company_id;
}
}
AuthServiceProvider
protected $policies = [
'App\Models\User' => 'App\Policies\CompanyAdmin\UserPolicy',
'App\Models\Company' => 'App\Policies\CompanyAdmin\CompanyPolicy',
'App\Models\Team' => 'App\Policies\CompanyAdmin\TeamPolicy',
'App\Models\Department' => 'App\Policies\CompanyAdmin\DepartmentPolicy',
'App\Models\Location' => 'App\Policies\CompanyAdmin\LocationPolicy',
'App\Models\Division' => 'App\Policies\CompanyAdmin\DivisionPolicy',
'App\Models\Costcenter' => 'App\Policies\CompanyAdmin\CostcenterPolicy',
'App\Models\Workplace' => 'App\Policies\CompanyAdmin\WorkplacePolicy',
'App\Models\Product' => 'App\Policies\CompanyAdmin\ProductPolicy',
'App\Models\Project\Action' => 'App\Policies\Project\ActionPolicy',
'App\Models\Project\Project' => 'App\Policies\Project\ProjectPolicy',
];
CreateActionRequest
namespace App\Http\Requests\Project;
use Illuminate\Foundation\Http\FormRequest;
class CreateActionRequest extends FormRequest
{
public function authorize()
{
return true;
}
public function rules()
{
return [
'name' => 'required|min:3',
];
}
}
All policies are working except ActionPolicy and ProjectPolicy. I added in the policy a __construct()
method to check if the policy is called. But ActionPolicy and ProjectPolicy are not working. How can I search the error? I tried with dd()
but I always got the message:
This action is unauthorized
Since you are injecting CreateActionRequest
instead of Request
that means you are defining your own set of rules to authorize the FormRequest
which comes inside of your method. Further it means that you gotta define a few rules which the "FormRequest
" has to pass in order to EVEN reach your controller, this is a nice concept that I like about Laravel since the code is not centralized, but rather spread and every layer has it's own responsibility. Now, you don't have to call any method from your CreateActionRequest
nor you have to write any code regarding that class in your controller, because Laravel runs authorize
method by default
before allowing the Request
to reach your controller, before running authorize
method in your CreateActionRequest
it runs rules
method which verifies that all the given fields pass the expressions you assigned them, so the execution is something like this CreateActionRequest => rules => authorize => IF(authorized) Controller ELSE Not authorized
, hope that makes sense. In order to fix your code:
1.) Remove $this->authorize('store', $project);
This will allow you to pass not authorized
error in case your name
passes the truth test inside of rules
method inside of your CreateActionRequest
. If you wish to utilize your Action Policy
you will need to hook up your custom Request
(CreateActionRequest) with it and this is how:
public function authorize()
{
$store = $this->route('project');
//The above line will return Project object if your mapping is correct
//If it's not it will return the value you passed to your route for {project}
return $this->user() && $this->user()->can('store', $store);
}
EDIT:
Here is the link where you can see how to properly authorize and connect policy with CreateActionRequest