'Laravel policies strangely not working

The point is simple: I have a UserPolicy method that checks if a user wants to edit his/her own profile. So I did like this:

public function update(User $user, User $model)
{
    return $user->id === $model->id;
}

And this is called in a UserController as it follows:

public function edit(User $user)
{
    $this->authorize('update', $user);
    return view('users.edit')->with('user', $user);
}

Everything is the same in a PostController and a PostPolicy, meant to check if a user can edit his/her own post and it works. The only difference is in their signature, since one has two users (the first one is the currently authenticated user injected by Laravel and the other is the instance I want to check it with) and the other has the above seen automatically injected authenticated user and a post instance. Anyway, it throws:

Symfony \ Component \ HttpKernel \ Exception \ AccessDeniedHttpException

This action is unauthorized.

I tried to dd($model) but I got the same exception. Why? Thanks in advance!

EDIT

In my AuthServiceProvider is all set up, too:

    protected $policies = [
    // 'App\Model' => 'App\Policies\ModelPolicy',
    Post::class => PostPolicy::class,
    User::class => UserPolicy::class,
];

And so is my routes.php:

// Authentication Routes...
$this->post('login', 'Auth\LoginController@login')->name('login');
$this->post('logout', 'Auth\LoginController@logout')->name('logout');

// Registration Routes...
$this->post('register', 'Auth\RegisterController@register')->name('register');

// Password Reset Routes...
$this->get('password/reset', 'Auth\ForgotPasswordController@showLinkRequestForm')->name('password.request');
$this->post('password/email', 'Auth\ForgotPasswordController@sendResetLinkEmail')->name('password.email');
$this->get('password/reset/{token}', 'Auth\ResetPasswordController@showResetForm')->name('password.reset');
$this->post('password/reset', 'Auth\ResetPasswordController@reset');

Route::get('/', 'HomeController@index')->name('home');

Route::resource('posts', 'PostController');

Route::resource('users', 'UserController')->except('index', 'create', 'store');

Everything above is called right here:

@if ($user->id == Auth::id())
    <a class="btn btn-link float-right p-0"
    href="{{ route('users.edit', Auth::id()) }}">

        <i class="fas fa-cog"></i>
        Edit profile
    </a>

    <br><br><br>
@endif


Solution 1:[1]

I'm giving an answer myself: I tried to write the model and policy's full paths instead of registering the policies by the classes' names and it works (I don't know why, of course).

I did like this:

protected $policies = [
    // 'App\Model' => 'App\Policies\ModelPolicy',
    'App\User' => 'App\Policies\UserPolicy',
    'App\Post' => 'App\Policies\PostPolicy',
];

Anyway, thanks everyone for trying to help me. Hope it will help someone else one day!

Solution 2:[2]

I just solved the same issue after fighting a whole day. Using full paths for register did not work for me. I fixed it by modifying my routes. I post my solution here hoping it may help someone someday.

If your routes are not protected by the authentication middleware, an AccessDeniedException will be thrown before applying your policies. The reason is that if your request comes in directly, you will never be treated as a logged-in user, so that you will be kicked off when trying to call $this->authorize('update') within the controller.

Route::middleware("auth:sanctum")->group(function () {
    Route::post('/member/{id}', [MembersController::class, 'update']);
    // ... and other path.
});

Sources

This article follows the attribution requirements of Stack Overflow and is licensed under CC BY-SA 3.0.

Source: Stack Overflow

Solution Source
Solution 1
Solution 2 lijishan