Framework: Using $this->authorize inside controller __construct prevents php artisan route:list

Created on 21 Sep 2015  路  5Comments  路  Source: laravel/framework

This is the error:

位 php artisan route:list -vvv



  [Symfony\Component\HttpKernel\Exception\HttpException]
  This action is unauthorized.



Exception trace:
 () at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Auth\Access\AuthorizesRequests.php:74
 Dolce\Http\Controllers\Controller->createGateUnauthorizedException() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Auth\Access\AuthorizesRequests.php:24
 Dolce\Http\Controllers\Controller->authorize() at C:\Repositories\Dolce\app\Http\Controllers\UserController.php:24
 Dolce\Http\Controllers\UserController->__construct() at n/a:n/a
 ReflectionClass->newInstanceArgs() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Container\Container.php:775
 Illuminate\Container\Container->build() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Container\Container.php:626
 Illuminate\Container\Container->make() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Application.php:674
 Illuminate\Foundation\Application->make() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Console\RouteListCommand.php:170
 Illuminate\Foundation\Console\RouteListCommand->getControllerMiddleware() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Console\RouteListCommand.php:151
 Illuminate\Foundation\Console\RouteListCommand->getMiddleware() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Console\RouteListCommand.php:119
 Illuminate\Foundation\Console\RouteListCommand->getRouteInformation() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Console\RouteListCommand.php:89
 Illuminate\Foundation\Console\RouteListCommand->getRoutes() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Console\RouteListCommand.php:76
 Illuminate\Foundation\Console\RouteListCommand->fire() at n/a:n/a
 call_user_func_array() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Container\Container.php:502
 Illuminate\Container\Container->call() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Console\Command.php:150
 Illuminate\Console\Command->execute() at C:\Repositories\Dolce\vendor\symfony\console\Command\Command.php:259
 Symfony\Component\Console\Command\Command->run() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Console\Command.php:136
 Illuminate\Console\Command->run() at C:\Repositories\Dolce\vendor\symfony\console\Application.php:878
 Symfony\Component\Console\Application->doRunCommand() at C:\Repositories\Dolce\vendor\symfony\console\Application.php:195
 Symfony\Component\Console\Application->doRun() at C:\Repositories\Dolce\vendor\symfony\console\Application.php:126
 Symfony\Component\Console\Application->run() at C:\Repositories\Dolce\vendor\laravel\framework\src\Illuminate\Foundation\Console\Kernel.php:100
 Illuminate\Foundation\Console\Kernel->handle() at C:\Repositories\Dolce\artisan:36

I assumed that I can place the authorize call in the constructor since the permission I set applies to all controller methods. Is this the expected behavior?

Most helpful comment

seems like this might help explain why.

from Taylor:

It鈥檚 very bad to use session or auth in your constructor as no request has happened yet and session and auth are INHERENTLY tied to an HTTP request. You should receive this request in an actual controller method which you can call multiple times with multiple different requests. By forcing your controller to resolve session or auth information in the constructor you are now forcing your entire controller to ignore the actual incoming request which can cause significant problems when testing, etc.

All 5 comments

Why don't you put your authorization into a middleware and pass that in the Route::* call?

@thekonz Can you provide an example on how to use the Gate::allow or something like that in the routes.php?

@nicozimmermann94 just look at the docs https://laravel.com/docs/5.2/middleware#registering-middleware

this shows, how you can use authorization middleware without using the constructor of your controller.

Hi @GrahamCampbell I'm confused why this was closed and hoping you could clarify maybe something I missed?

say I have a model with a policy that defines a method like administer

public function administer(User $user)
{
    return $user->someAdminLogic();
}

why is it that this does not work in my controller?

public function __construct()
{
    $this->authorize('administer', MyModel::class);
}

but does work when defined on the route as middleware?

Route::resource('mymodels', 'MyModelsController', ['middleware' => 'can:administer,App\MyModel']);

IMO it seems to make sense to keep the authorization business logic on the controller methods with which it pertains, instead of copied or grouped everywhere a route references the controller. Is it really the expected behavior to always reject authorizations in the constructor, regardless of policy? Surely I've got my wires crossed somewhere.

thanks for your time

seems like this might help explain why.

from Taylor:

It鈥檚 very bad to use session or auth in your constructor as no request has happened yet and session and auth are INHERENTLY tied to an HTTP request. You should receive this request in an actual controller method which you can call multiple times with multiple different requests. By forcing your controller to resolve session or auth information in the constructor you are now forcing your entire controller to ignore the actual incoming request which can cause significant problems when testing, etc.

Was this page helpful?
0 / 5 - 0 ratings

Related issues

SachinAgarwal1337 picture SachinAgarwal1337  路  3Comments

digirew picture digirew  路  3Comments

Fuzzyma picture Fuzzyma  路  3Comments

lzp819739483 picture lzp819739483  路  3Comments

PhiloNL picture PhiloNL  路  3Comments