Hello,
I'm trying to add policies to my project and I'm getting this weird issue.
I had the Controller and Route::resource working with auth just fine.
I created the Policy with artisan. Then I added a before function to allow admins to access everything.
Finally I added
public function __construct()
{
$this->middleware('auth');
$this->authorizeResource(Fee::class, 'fees');
// dd($this->getMiddleware());
}
to my controller's __construct method and the policy binding in AuthServiceProvider
protected $policies = [
// 'App\Models\Model' => 'App\Policies\ModelPolicy',
'App\Models\Fee' => 'App\Policies\FeePolicy',
];
The Policy file is simple
<?php
namespace App\Policies;
use App\Models\Fee;
use App\Models\User;
use Illuminate\Auth\Access\HandlesAuthorization;
use Log;
class FeePolicy
{
/**
* The before method of a policy class will not be called if the
* class doesn't contain a method with a name matching the name of the ability being checked.
*/
use HandlesAuthorization;
protected $authorizedRoles = [
'platform-manager',
];
/**
* Perform pre-authorization checks.
*
* @param \App\Models\User $user
* @param string $ability
* @return void|bool
*/
public function before(User $user)
{
// return null;
//when viewing the index route this works as expected
//when trying to view a specific item /fees/1 or /fees/1/edit or delete it never gets here
Log::info('checking role BEFORE entering specific policy actions');
if ($user->hasAnyRole($this->authorizedRoles)) {
return true;
}
}
/**
* Determine whether the user can view any models.
*
* @param \App\Models\User $user
* @return \Illuminate\Auth\Access\Response|bool
*/
public function viewAny(User $user)
{
//if I return null in before() we get in this one
Log:info('Running fee policy INDEX');
return true;
}
/**
* Determine whether the user can view the model.
*
* @param \App\Models\User $user
* @param \App\Models\Fee $fee
* @return \Illuminate\Auth\Access\Response|bool
*/
public function view(User $user, Fee $fee)
{
//it never gets to log this
Log:info('Running fee policy for VIEW');
return true;
}
/**
* Determine whether the user can create models.
*
* @param \App\Models\User $user
* @return \Illuminate\Auth\Access\Response|bool
*/
public function create(User $user)
{
return true;
}
/**
* Determine whether the user can update the model.
*
* @param \App\Models\User $user
* @param \App\Models\Fee $fee
* @return \Illuminate\Auth\Access\Response|bool
*/
public function update(User $user, Fee $fee)
{
return true;
}
/**
* Determine whether the user can delete the model.
*
* @param \App\Models\User $user
* @param \App\Models\Fee $fee
* @return \Illuminate\Auth\Access\Response|bool
*/
public function delete(User $user, Fee $fee)
{
return true;
}
/**
* Determine whether the user can restore the model.
*
* @param \App\Models\User $user
* @param \App\Models\Fee $fee
* @return \Illuminate\Auth\Access\Response|bool
*/
public function restore(User $user, Fee $fee)
{
return true;
}
/**
* Determine whether the user can permanently delete the model.
*
* @param \App\Models\User $user
* @param \App\Models\Fee $fee
* @return \Illuminate\Auth\Access\Response|bool
*/
public function forceDelete(User $user, Fee $fee)
{
return true;
}
}
This is the output when I do dd($this->getMiddleware() in the Controller's __construct.
array:6 [▼
0 => array:2 [▼
"middleware" => "auth"
"options" => []
]
1 => array:2 [▼
"middleware" => "can:viewAny,App\Models\Fee"
"options" => array:1 [▼
"only" => array:1 [▼
0 => "index"
]
]
]
2 => array:2 [▼
"middleware" => "can:view,fees"
"options" => array:1 [▼
"only" => array:1 [▶]
]
]
3 => array:2 [▼
"middleware" => "can:create,App\Models\Fee"
"options" => array:1 [▼
"only" => array:2 [▼
0 => "create"
1 => "store"
]
]
]
4 => array:2 [▼
"middleware" => "can:update,fees"
"options" => array:1 [▼
"only" => array:2 [▶]
]
]
5 => array:2 [▼
"middleware" => "can:delete,fees"
"options" => array:1 [▼
"only" => array:1 [▼
0 => "destroy"
]
]
]
]
Also the output of php artisan routes:list --json is:
[
{
"domain": null,
"method": "GET|HEAD",
"uri": "fees",
"name": "fees.index",
"action": "App\Http\Controllers\FeeController@index",
"middleware": [
"web",
"auth",
"can:viewAny,App\Models\Fee"
]
},
{
"domain": null,
"method": "POST",
"uri": "fees",
"name": "fees.store",
"action": "App\Http\Controllers\FeeController@store",
"middleware": [
"web",
"auth",
"can:create,App\Models\Fee"
]
},
{
"domain": null,
"method": "GET|HEAD",
"uri": "fees/create",
"name": "fees.create",
"action": "App\Http\Controllers\FeeController@create",
"middleware": [
"web",
"auth",
"can:create,App\Models\Fee"
]
},
{
"domain": null,
"method": "GET|HEAD",
"uri": "fees/{fee}",
"name": "fees.show",
"action": "App\Http\Controllers\FeeController@show",
"middleware": [
"web",
"auth",
"can:view,fees"
]
},
{
"domain": null,
"method": "PUT|PATCH",
"uri": "fees/{fee}",
"name": "fees.update",
"action": "App\Http\Controllers\FeeController@update",
"middleware": [
"web",
"auth",
"can:update,fees"
]
},
{
"domain": null,
"method": "DELETE",
"uri": "fees/{fee}",
"name": "fees.destroy",
"action": "App\Http\Controllers\FeeController@destroy",
"middleware": [
"web",
"auth",
"can:delete,fees"
]
},
{
"domain": null,
"method": "GET|HEAD",
"uri": "fees/{fee}/edit",
"name": "fees.edit",
"action": "App\Http\Controllers\FeeController@edit",
"middleware": [
"web",
"auth",
"can:update,fees"
]
}
]
Which seems to me that the middleware is registered correctly so it should at least get inside the Policy function and I would be able to see the Log. But not the case.
I can't find anything related to this, so any ideas on where I've dropped the ball?
What stumbles me is that for the index/create/store route the whole flow works fine, but for the rest of the routes it just doesn't and the User is passed correctly to the Policy since the before() works. On view or edit or delete I get 403 unauthorized.