Be part of JetBrains PHPverse 2026 on June 9 – a free online event bringing PHP devs worldwide together.

deshiloh's avatar

Policy issues

Hi,

i searched for a solution here before to post, but i didn't find the fix.

i'm trying to add policies in my laravel application.

I created UserPolicy to use with my resource controller (UserController). In the --construct of my UserController i put :

$this->authorizeResource(User::class, 'users'); // route's name

the view's policy method works, but update doesn't work. I always have 403 error. Even with return true; I don't see where i'm doing wrong. Can you help me please ?

0 likes
34 replies
deshiloh's avatar

Hi thanks for your answer.

i'll show you.

<?php

namespace App\Policies;

use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class UserPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can view any models.
     *
     * @param  User  $user
     * @return mixed
     */
    public function viewAny(User $user)
    {
        return true;
    }

    /**
     * Determine whether the user can view the model.
     *
     * @param  User  $user
     * @param  User  $model
     * @return mixed
     */
    public function view(User $user, User $model)
    {
        return true;
    }

    /**
     * Determine whether the user can create models.
     *
     * @param  User  $user
     * @return mixed
     */
    public function create(User $user)
    {
        //
    }

    /**
     * Determine whether the user can update the model.
     *
     * @param  User  $user
     * @param  User  $model
     * @return mixed
     */
    public function update(User $user, User $model)
    {
        return true;
    }

    /**
     * Determine whether the user can delete the model.
     *
     * @param  User  $user
     * @param  User  $model
     * @return mixed
     */
    public function delete(User $user, User $model)
    {
        //
    }

    /**
     * Determine whether the user can restore the model.
     *
     * @param  User  $user
     * @param  User  $model
     * @return mixed
     */
    public function restore(User $user, User $model)
    {
        //
    }

    /**
     * Determine whether the user can permanently delete the model.
     *
     * @param  User  $user
     * @param  User  $model
     * @return mixed
     */
    public function forceDelete(User $user, User $model)
    {
        //
    }
}

The AuthServiceProvider :

<?php

namespace App\Providers;

use App\Models\User;
use App\Policies\UserPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * The policy mappings for the application.
     *
     * @var array
     */
    protected $policies = [
        User::class => UserPolicy::class
    ];

    /**
     * Register any authentication / authorization services.
     *
     * @return void
     */
    public function boot()
    {
        $this->registerPolicies();

        //
    }
}

And my Controller :

<?php

namespace App\Http\Controllers\User;

use App\Http\Controllers\HomeController as Controller;
use App\Http\Requests\StoreUser;
use App\Models\User;
use Faker\Factory;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\View\View;

class UserController extends Controller
{

    public function __construct()
    {
        parent::__construct();
        $this->authorizeResource(User::class, 'users');
    }

    /**
     * Liste de tous les utilisateurs
     * @return \Illuminate\Contracts\View\Factory|View
     */
    public function index()
    {
        $users = User::All();
        return view('users.listing', [
            'users' => $users
        ]);
    }

    public function create()
    {
        return view('users.add');
    }

    public function store(StoreUser $request)
    {
        $request->validated();
        $datas = $request->except(['_token']);
        $datas['password']  = Hash::make($datas['password']);
        $datas['email']     = Factory::create()->safeEmail;
        $user = new User();
        $user->fill($datas);
        $user->save();
        return redirect()->route('users.index')->with('success', 'L\'utilisateur a bien été ajouté.');
    }

    /**
     * Form Modifie un utilisateur
     * @param $id
     * @return \Illuminate\Contracts\View\Factory|View
     */
    public function edit($id)
    {
        $user = User::findOrFail($id);
        return view('users.update', [
            'user'  => $user
        ]);
    }

    public function update(StoreUser $request, $user)
    {
        /** @var User $user */
        $userData = User::findOrFail($user);
        $request->validated();
        $datas = $request->except(['_token', '_method', 'password_confirmation']);
        if ($request->has('password') && $request->input('password') !== null) {
            $datas['password'] = Hash::make($datas['password']);
        } else {
            unset($datas['password']);
        }
        $userData->fill($datas);
        $userData->update();
        $request->session()->flash('success', 'Mise à jour effectuée.');
        return redirect()->route('users.edit', ['user' => $userData->id])->with('success', 'L\'utlisateur a été modifié.');
    }

    /**
     * Suppression d'un utilisateur
     * @param $id
     * @param Request $request
     * @return \Illuminate\Http\RedirectResponse
     */
    public function destroy($id, Request $request)
    {
        try {
            User::findOrFail($id)->delete();
            return redirect()->route('users.index')->with('success', 'L\'utilisateur a bien été supprimé.');
        } catch (\Exception $exception) {
            return redirect()->route('users.index')->with('success', 'Une erreur est survenue : '.$exception->getMessage());
        }
    }
}
Nakov's avatar

@deshiloh just to try out as everything seems okay to me, so if you have:

Route::resource('users', 'UsersController');

Then the param is actually not singular form {user}

So try this instead:

$this->authorizeResource(User::class, 'user');
bugsysha's avatar

Your form request App\Http\Requests\StoreUser probably returns false for authorization. Change it to true.

deshiloh's avatar

Didn't change anything

<?php

namespace App\Http\Requests;

use Illuminate\Foundation\Http\FormRequest;

class StoreUser extends FormRequest
{
    /**
     * Determine if the user is authorized to make this request.
     *
     * @return bool
     */
    public function authorize()
    {
        return true;
    }

    /**
     * Get the validation rules that apply to the request.
     *
     * @return array
     */
    public function rules()
    {
        return [
            'name'      => 'required|string',
            'email'     => 'nullable|email',
            'job'       => 'required|string',
            'login'     => 'nullable|unique:users',
            'password'  => 'nullable|confirmed'
        ];
    }
}
bugsysha's avatar

Have you tried removing

parent::__construct();
bugsysha's avatar

Also try returning true from all methods in UserPolicy.

bugsysha's avatar

Looking at this method

    public function authorizeResource($model, $parameter = null, array $options = [], $request = null)
    {
        $parameter = $parameter ?: Str::snake(class_basename($model));

you can use it without second parameter. Have you tried without it?

bugsysha's avatar

Post results for

    public function __construct()
    {
        $this->authorizeResource(User::class);
        dd($this->getMiddleware());
    }
deshiloh's avatar
```array:6 [▼
  0 => array:2 [▼
    "middleware" => "auth"
    "options" => []
  ]
  1 => array:2 [▼
    "middleware" => "can:viewAny,App\Models\User"
    "options" => array:1 [▼
      "only" => array:1 [▼
        0 => "index"
      ]
    ]
  ]
  2 => array:2 [▼
    "middleware" => "can:view,user"
    "options" => array:1 [▼
      "only" => array:1 [▼
        0 => "show"
      ]
    ]
  ]
  3 => array:2 [▼
    "middleware" => "can:create,App\Models\User"
    "options" => array:1 [▼
      "only" => array:2 [▼
        0 => "create"
        1 => "store"
      ]
    ]
  ]
  4 => array:2 [▼
    "middleware" => "can:update,user"
    "options" => array:1 [▼
      "only" => array:2 [▼
        0 => "edit"
        1 => "update"
      ]
    ]
  ]
  5 => array:2 [▼
    "middleware" => "can:delete,user"
    "options" => array:1 [▼
      "only" => array:1 [▼
        0 => "destroy"
      ]
    ]
  ]
]
Nakov's avatar

@deshiloh I think I reproduced what you have now..

Are you trying this with unauthorized user?

Because the authorization requires the user to be authorized otherwise it always returns 403.

You will have to set the User to be optional like this for example:

public function viewAny(User $user = null)
4 likes
ajagabos007's avatar

@Nakov your post of 3 years ago at this time that I am replying worked for me. Thanks.

deshiloh's avatar

the viewAny works since the beginning.

I tried it anyway.. still doesn't work (tried on the viewAny and update give the same).

bugsysha's avatar

Are you trying this with unauthorized user?

That would be perfect 🤦🏻‍♂️

Nakov's avatar
Nakov
Best Answer
Level 73

@deshiloh I cloned your project.

And used this:

public function __construct()
    {
        $this->authorizeResource(User::class, 'user');
    }

public function edit(User $user)
    {
        return view('users.update', [
            'user'  => $user
        ]);
    }

So the route model binding is used. And the edit page opens correctly.

Same for update

public function update(StoreUser $request, User $user)
bugsysha's avatar

Since he does not have any auth middleware in UserController or web.php I assume that you are right @nakov. And those routes that he is saying that they work are the ones that do not require logged in user to be passed to policies.

deshiloh's avatar

@bugsysha I have the auth middleware, i created HomeController who have the middleware, look closer you will see that i've done.

@nakov wait, you didn't change anything and it's working when you tried ?

bugsysha's avatar

I have the auth middleware, i created HomeController who have the middleware, look closer you will see that i've done.

I saw that but you only have it on HomeController.

Nakov's avatar

@deshiloh compare my code from above... there are changes for sure.

And what @bugsysha said is true. The auth middleware is applied to the home controller but not to the other routes nor groups..

deshiloh's avatar

To don't repeat myself in the coding, i created HomeController and UserController (as some other controller i need to be auth) are extended HomeController (HomeController extends of Controller's Lavarel).

So, in that way, UserController should use auth middleware isn't it ?

Nakov's avatar

@deshiloh yup, but your UserController is not extending from the HomeController.

deshiloh's avatar

@nakov

I don't understand why i had to pass User $user, why it didn't worked before ?

deshiloh's avatar

@nakov Yes he does in that way :

use App\Http\Controllers\HomeController as Controller;
bugsysha's avatar

use App\Http\Controllers\HomeController as Controller;

Strange but cool and easy to miss.

bugsysha's avatar

I don't understand why i had to pass User $user, why it didn't worked before ?

You have to have explicit model binding when you use Route::resource or how the framework is going to know/guess which model that refers to.

For example, what if you store all models under different namespace?

Please or to participate in this conversation.