Elwin
Elwin

Reputation: 491

'Authorize' only specific routes of a resource

There is this method authorizeResource() which applies specific policies to all routes (except the index route). Is there a way to apply policies only on specific routes, analogous to this function:

Route::resource('photo', 'PhotoController', ['only' => [
    'index', 'show'
]]);

Upvotes: 3

Views: 4030

Answers (3)

Gustavo Straube
Gustavo Straube

Reputation: 3861

Despite pointed out by @JeffPucket in his answer, the only option didn't work for me. I'm running Laravel 5.5 and what did work was the inverse logic:

public function __construct()
{
    $this->authorizeResource(Photo::class, null, [
        'except' => [ 'index', 'show' ],
    ]);
}

Notice that you should pass to that option the actions (controller's methods) you don't want to apply your policy. In this case, index and show will bypass the authorization middleware.

Just for comparison, here are the results from php artisan route:list when using each option:

only

+--------+-----------+------------------------+-----------------+------------------------------------------------+--------------------------------------------------+
| Domain | Method    | URI                    | Name            | Action                                         | Middleware                                       |
+--------+-----------+------------------------+-----------------+------------------------------------------------+--------------------------------------------------+
|        | POST      | comment                | comment.store   | App\Http\Controllers\CommentController@store   | web,auth,can:create,App\Http\Controllers\Comment |
|        | GET|HEAD  | comment                | comment.index   | App\Http\Controllers\CommentController@index   | web,auth,can:view,App\Http\Controllers\Comment   |
|        | GET|HEAD  | comment/create         | comment.create  | App\Http\Controllers\CommentController@create  | web,auth,can:create,App\Http\Controllers\Comment |
|        | GET|HEAD  | comment/{comment}      | comment.show    | App\Http\Controllers\CommentController@show    | web,auth,can:view,comment                        |
|        | PUT|PATCH | comment/{comment}      | comment.update  | App\Http\Controllers\CommentController@update  | web,auth,can:update,comment                      |
|        | DELETE    | comment/{comment}      | comment.destroy | App\Http\Controllers\CommentController@destroy | web,auth,can:delete,comment                      |
|        | GET|HEAD  | comment/{comment}/edit | comment.edit    | App\Http\Controllers\CommentController@edit    | web,auth,can:update,comment                      |
+--------+-----------+------------------------+-----------------+------------------------------------------------+--------------------------------------------------+

except

+--------+-----------+------------------------+-----------------+------------------------------------------------+--------------------------------------------------+
| Domain | Method    | URI                    | Name            | Action                                         | Middleware                                       |
+--------+-----------+------------------------+-----------------+------------------------------------------------+--------------------------------------------------+
|        | POST      | comment                | comment.store   | App\Http\Controllers\CommentController@store   | web,auth,can:create,App\Http\Controllers\Comment |
|        | GET|HEAD  | comment                | comment.index   | App\Http\Controllers\CommentController@index   | web,auth                                         |
|        | GET|HEAD  | comment/create         | comment.create  | App\Http\Controllers\CommentController@create  | web,auth,can:create,App\Http\Controllers\Comment |
|        | GET|HEAD  | comment/{comment}      | comment.show    | App\Http\Controllers\CommentController@show    | web,auth                                         |
|        | PUT|PATCH | comment/{comment}      | comment.update  | App\Http\Controllers\CommentController@update  | web,auth,can:update,comment                      |
|        | DELETE    | comment/{comment}      | comment.destroy | App\Http\Controllers\CommentController@destroy | web,auth,can:delete,comment                      |
|        | GET|HEAD  | comment/{comment}/edit | comment.edit    | App\Http\Controllers\CommentController@edit    | web,auth,can:update,comment                      |
+--------+-----------+------------------------+-----------------+------------------------------------------------+--------------------------------------------------+

As you can see above, the middleware is only applied to specific routes when using except.

Perhaps this is a bug in the framework. But it's hard to confirm that since this option doesn't seem to be documented. Even details on authorizeResource() method are non-existing.

Upvotes: 12

Jeff Puckett
Jeff Puckett

Reputation: 40861

Yes, authorizeResource accepts an $options array as a third parameter. Just pass null for the second argument and the syntax for options is the same as it is for route middleware.

public function __construct()
{
    $this->authorizeResource(Photo::class, null, [
        'only' => ['create', 'store'],
    ]);
}

Upvotes: 4

apokryfos
apokryfos

Reputation: 40673

You can realistically define middleware in the controller:

public PhotoController extends Controller {
    public function __construct() {
         $this->middleware("can:save,photo")->only(["save","edit"]);   //You get the idea
    }
}

This assumes you've written a proper policy (check https://laravel.com/docs/5.4/authorization)

Upvotes: 2

Related Questions