Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Laravel authorization via middleware

I created a policy in laravel 5.3 with this two actions:

class ProjectPolicy {
   ...
   public function index(User $user)
   {
      return true;
   }
   public function create(User $user)
   {
      return true;
   }
   ...
}

and then I tried to make authorization via route group middleware:

Route::group(['middleware' => ['can:index,create,App\Project']], function () {
    Route::resource('projects', 'ProjectController');
});

ofcourse I have created Project model and controller correctly, but calling index and create actions always returns 403 forbidden response. where is the problem?

Update:

removing one of actions from route middleware, results correct response. something like this:

Route::group(['middleware' => ['can:index,App\Project']], function () {
    Route::resource('projects', 'ProjectController');
});
like image 793
Hamid Zamani Avatar asked Nov 01 '16 21:11

Hamid Zamani


People also ask

What is auth middleware Laravel?

Using the Auth Middleware Middlewares provide a convenient mechanism for filtering HTTP requests entering your application. For example, Laravel includes a middleware that verifies the user of your application is authenticated. If the user is not authenticated, the middleware will redirect the user to the login screen.

How do I authorize Laravel?

Laravel provides two primary ways of authorizing actions: gates and policies. Think of gates and policies like routes and controllers. Gates provide a simple, closure-based approach to authorization while policies, like controllers, group logic around a particular model or resource.

What is difference between authentication and authorization in Laravel?

Thus, authentication involves checking the validity of the user credentials, and authorization involves checking the rights and permissions over the resources that an authenticated user has.


2 Answers

Looking through the docs the can middleware doesn't really lend itself to resources. You could use multiple middleware calls on the group but this would mean that your use would require all privileges to access the routes.

Your alternatives are:

Add $this->authorize(new App\Project) to your index and create methods in your controller. Laravel will use reflection to figure out what policy to use based on the method it is called from.

Or

In the __construct() method of your controller you could use:

$this->authorizeResource(App\Project::class); 

This will require you to create update, view and delete methods inside your Policy class. Each of these methods will be passed User $user, Project $project e.g.

public function view(User $user, Project $project)
{
   return true;
}

FYI, if you leave off the method name with authorize() or you use authorizeResource() Laravel will map certain method names to different policy methods i.e. :

[
  //ControllerMethod => PolicyMethod
    'show'    => 'view',
    'create'  => 'create',
    'store'   => 'create',
    'edit'    => 'update',
    'update'  => 'update',
    'destroy' => 'delete',
];

You can override this by adding a resourceAbilityMap() method to your controller and returning a different array to the one above.

Hope this helps!

like image 157
Rwd Avatar answered Oct 08 '22 16:10

Rwd


Spend hours on that ... If your controller method does not take a Model as parameter, you also have to override the resourceMethodsWithoutModels().

protected function resourceAbilityMap()
{
    Log::info("Inside resourceAbilityMap()");
    return array_merge(parent::resourceAbilityMap(), [
        //ControllerMethod => PolicyMethod
        'index' => 'index',
        'search' => 'search'
    ]);
}


protected function resourceMethodsWithoutModels(){
    return array_merge(parent::resourceMethodsWithoutModels(), [
        'search'
    ]);
}
like image 32
Juljan Avatar answered Oct 08 '22 14:10

Juljan