Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

laravel authorizeResource always denies access

I have created a resource controller for an API endpoint. I have also created a corresponding policy for the model.

If I do a per method authorization check using

$this->authorize('delete', $asset);

then it works as expected. But if I add the following to the construct, I always get a 403 forbidden. Not sure what I am missing as the following should apply the authorization for all methods.

$this->authorizeResource(Asset::class, 'asset');

This is what my route looks like:

Route::group(['middleware' => ['auth:api']], function () {
    Route::Resource('asset', 'AssetsApiController');
});

My policy is registered like this:

protected $policies = [
    Asset::class => AssetPolicy::class,
];

My policy method for deleting is

public function delete(User $user, Asset $asset)
{
    return true;
}

The API controller constructor looks like this:

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

The API controller method is

public function destroy($assetID)
{
    $asset = Asset::findOrFail($assetID);
    $asset->delete();
}

And my routes are

| GET|HEAD  | api/asset              | asset.index   | App\Http\Controllers\AssetsApiController@index   | api,auth:api                      |
| POST      | api/asset              | asset.store   | App\Http\Controllers\AssetsApiController@store   | api,auth:api,can:create,App\Asset |
| GET|HEAD  | api/asset/create       | asset.create  | App\Http\Controllers\AssetsApiController@create  | api,auth:api,can:create,App\Asset |
| PUT|PATCH | api/asset/{asset}      | asset.update  | App\Http\Controllers\AssetsApiController@update  | api,auth:api,can:update,asset     |
| DELETE    | api/asset/{asset}      | asset.destroy | App\Http\Controllers\AssetsApiController@destroy | api,auth:api,can:delete,asset     |
| GET|HEAD  | api/asset/{asset}      | asset.show    | App\Http\Controllers\AssetsApiController@show    | api,auth:api,can:view,asset       |
| GET|HEAD  | api/asset/{asset}/edit | asset.edit    | App\Http\Controllers\AssetsApiController@edit    | api,auth:api,can:update,asset     |
| GET|HEAD  | assets                 |               | App\Http\Controllers\AssetsController@index      | web                               |                                               

I guess I am missing something but I can't see it, the gate is being shown as denied in Telescope. the only strange thing is that the serveNova middleware seems to be the source of the issue.

Time May 8th 2019, 10:51:37 AM (14m ago)
Hostname core-hosp
Ability delete
Result denied
Location /home/vagrant/code/nova/src/Http/Middleware/ServeNova.php:25
Request View Request
Tags Auth:1

like image 460
JaChNo Avatar asked May 08 '19 10:05

JaChNo


4 Answers

I've described my lessons learn with this tiring problem here: https://github.com/laravel/framework/issues/22847#issuecomment-521308861. Maybe somebody will find it useful.

like image 65
Jakub Avatar answered Nov 15 '22 15:11

Jakub


I had the same issue and resolved it by changing the signature of the controller methods. By default controllers receive an integer $id to reference the model, while policies receive directly the model instance. My intuition is that the mapping can't be made between the controller and the policy.

So, I suggest to try changing your controller method to:

   public function destroy(Asset $asset)
    {
        $asset->delete();
    }

I don't know if it's a bug ? I didn't find docs about these method type signature conventions.

Updated on May 2021:

You can keep the $id as the default param, as you can allow the mapping b/t the controller and the policy by putting the authorization call after the finding the relevant model instance, like this:

public function destroy($id)
    {   
        $post = Post::find($id);//post instance is created b/4 going through policy.
        $this->authorize('delete',  $post);
        
        $post->delete();
        
        return Post::orderBy('created_at', 'desc')->paginate(3);
    }
like image 20
J4kim Avatar answered Nov 15 '22 15:11

J4kim


I found that getting the Model identifier parameter correct for authorizeResource was very fiddly. When the parameter is missing or not passed properly, the step before the Policy throws the error (not the Policy itself because the request never makes it to the Policy). In my case, that meant my CheckUserActive middleware was throwing the error, even though the mistake was in the Construct function of the Controller (not the Middleware). A few notes on the parameter that AuthorizeResource is looking for:

  1. Must be in lower case, even if the parameter is declared in upper case in your model.
  2. Must be a string (without the variable defining $ that is used in a lot of the examples.)
  3. Must be inside single tick quote marks.

For example:

$this->authorizeResource(Model::class, 'parameter');
like image 1
Peter Thomson Avatar answered Nov 15 '22 14:11

Peter Thomson


I solved this problem by removing the second parameter :

    public function __construct()
{
    $this->authorizeResource(Admin::class);
}
like image 1
Artin GH Avatar answered Nov 15 '22 15:11

Artin GH