In the Laravel 10 application, I use authorization of actions using Gate
, Policy
and Spatie
. The authorization of the event itself works fine, that is, where it is necessary and who it is necessary to let and does not let, respectively.
However, there was a small problem with the following case: the user is not an admin, has no privileges in any way, respectively, the before
method returns false
to check the administrator role. Next, a check should be run in the canEditStatus
method, from where a response with a code and an error message should be returned, since, again, the user does not have privileges. Instead of the message and the code, NULL
is returned, although the check really failed.
Below are the sources with the policy, controller, and response in Postman.
app\Policies\UserPolicy.php
<?php
namespace App\Policies;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use Illuminate\Auth\Access\Response;
class UserPolicy
{
use HandlesAuthorization;
private const ACCESS_ALLOW_MESSAGE = 'Ok';
private const ACCESS_DENIED_MESSAGE = 'Access denied';
public function before(User $user): bool
{
return $user->hasRole('admin'); // <-- it doesn't pass, that's right
}
public function canEditStatus(User $user): Response
{
if ($user->hasPermissionTo('edit status')) {
return $this->allow(self::ACCESS_ALLOW_MESSAGE, 200);
} else {
return $this->deny(self::ACCESS_DENIED_MESSAGE, 403); // <-- expect this answer
}
}
}
app\Http\Controllers\Api\UserController.php
<?php
namespace App\Http\Controllers\Api;
use App\Http\Requests\Api\UserUpdateRequest;
use App\Http\Resources\UserResource;
use App\Models\User;
use Illuminate\Database\RecordsNotFoundException;
use Illuminate\Http\JsonResponse;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Gate;
class UserController extends ApiController
{
public function update(UserUpdateRequest $updateRequest, string $id): JsonResponse
{
if ($updateRequest->has('is_active')) {
$authorize = Gate::inspect('can-edit-status', User::class);
if ($authorize->denied()) {
dd($authorize); // <-- authorization result dump
abort($authorize->code(), $authorize->message());
}
}
// next is the update logic
}
}
And, in fact, the response to the request from Postman:
As mentioned by the comment, it is possible this is not hitting the actual code. enter code here In my experience, laravel policies should be referenced exactly like the method definition and accessed through the user: