Laravel policy missing argument

В политике есть такой код:

   public function view(User $user, User $model): bool
    {
        return ($user->id == $model->id || in_array('read_users', $user->access));
    }

Первая модель - авторизированный пользователь, а вторая модель - просматриваемый пользователь. Ничего не работает, тк вторая модель не приходит в политику.

Запускается все в роутинге:

 Route::get('/{id}', [UserController::class, 'show'])->name('users.show')->middleware('can:view,' . User::class);

Model binding НЕ используется в контроллере, тк логика работы с бд вынесена в репозитории.


Ответы (1 шт):

Автор решения: Pavel

У вас есть логическая ошибка. Вы в мидлваре передаете название класса, а в политике проверяете с объектом. Если посмотреть документацию, то Model::class передается в методах политики где не требуется проверка объекта.

Т.е. если не брать мидлвар, а проверять в контроллере, то разница такая:

//  Передаете объект, так как требуется проверка объекта
if ($user->can('update', $post)) {
    //
}
// передаете название класса, так как объект не нужен при проверке
if ($user->can('create', Post::class)) {
    // Executes the "create" method on the relevant policy...
}

В вашей логике, вам нужен в политике объект. Т.е если вашу проверку перенести в контроллер, то будет примерно так:

if($user->can('view', $model)){
}

А что вы передаете в мидлвар? Не объект, а название класса.

Как перенести туда нужный объект? По простому никак, только если писать свой RBAC или делать обертку над дефолтным. Опять таки, в мидлвар вы все равно объект не передадите, но сможете в мидлваре достать параметры из реквеста и уже там создать модель для проверки.

Самый простой путь без костылей и наворотов - делать авторизацию в контроллере.

→ Ссылка