Issue
I have a the following routes defined:
//Leases
Route::resource('properties.leases', LeaseController::class)
->only(['show'])
->shallow();
//Invoices
Route::resource('leases.invoices', InvoiceController::class)
->only(['index', 'show'])
->shallow();
The above generates the following urls:
| GET|HEAD | leases/{lease} | App\Http\Controllers\LeaseController@show |
| GET|HEAD | leases/{lease}/invoices | App\Http\Controllers\InvoiceController@index |
| GET|HEAD | invoices/{invoice} | App\Http\Controllers\InvoiceController@show |
The relationships are as below:
Properties hasMany Leases.
Leases hasMany Invoices.
I am trying to authorize these routes, so only users who:
- Belongs to the same team that the "Leases" and "Invoices" also belong to.
- Is currently logged in on that team.
In my AuthServiceProvider
I have defined the following policies:
protected $policies = [
Lease::class => LeasePolicy::class,
Invoice::class => InvoicePolicy::class,
];
In my LeaseController
I have defined the authorization check:
public function __construct()
{
$this->authorizeResource(Lease::class, 'lease');
}
The LeasePolicy
looks like this:
public function view(User $user, Lease $lease)
{
//Does the current user belong to the team that the lease is associated with
//and is the user's current team the same one?
$team = $lease->property->team;
return $user->belongsToTeam($team) && $user->isCurrentTeam($team);
}
And in my InvoiceController
I have defined this:
public function __construct()
{
$this->authorizeResource(Invoice::class, 'invoice');
}
The InvoicePolicy
looks like this:
/**
* Path: leases/{lease}/{$invoice}
*/
public function viewAny(User $user)
{
//When users go to this path I can only access $user here.
//How to check if the user can even access the $lease.
}
/**
* Path: invoices/{$invoice}
*/
public function view(User $user, Invoice $invoice)
{
//Does the current user belong to the team that the lease is associated with
//and is the user's current team the same one?
$team = $invoice->lease->property->team;
return $user->belongsToTeam($team) && $user->isCurrentTeam($team);
}
In my application, I have a lot of routes that are "under" the /lease/{lease}/{model}
route, e.g.:
//Files
Route::resource('leases.files', FileController::class)
->only(['index'])
->shallow();
For these, how can I define my Policies
so only users who are allowed to view these ressources can get access?
Solution
As far as I know at the time I wrote this answer, the authorizeResource
cannot be used on some shallow nested methods (such as the index
, create
, & store
). So instead, you can call authorize
function on each method via controller helpers.
Or if you still want to use authorizeResource
, you can only call authorize
manually on some shallow nested methods like the following example:
class InvoiceController extends Controller
{
public function __construct()
{
$this->authorizeResource(Invoice::class, 'invoice');
}
/**
* Get the map of resource methods to ability names.
*
* @return array
*/
protected function resourceAbilityMap()
{
return collect(parent::resourceAbilityMap())
->except(['index', 'create', 'store'])
->all();
}
/**
* Display a listing of the resource.
*
* @param \App\Models\Lease $lease
* @return \Illuminate\Http\Response
*/
public function index(Lease $lease): Response
{
$this->authorize('view', $lease);
...
}
}
And by the way, if you want to make InvoicePolicy
simpler, you can also reuse LeasePolicy
like the following code:
class InvoicePolicy
{
use HandlesAuthorization;
public function __construct(
protected LeasePolicy $leasePolicy,
) {
}
/**
* Determine whether the user can view the model.
*
* @param \App\Models\User $user
* @param \App\Models\Invoice $invoice
* @return \Illuminate\Auth\Access\Response|bool
*/
public function view(User $user, Invoice $invoice): bool
{
return $this->leasePolicy->view($user, $invoice->lease);
}
}
Answered By - Yusuf T
0 Comments:
Post a Comment
Note: Only a member of this blog may post a comment.