我定义了以下路线:
//Leases
Route::resource('properties.leases', LeaseController::class)
->only(['show'])
->shallow();
//Invoices
Route::resource('leases.invoices', InvoiceController::class)
->only(['index', 'show'])
->shallow();
上面生成了以下网址:
| 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 |
关系如下:
Properties hasMany Leases.
Leases hasMany Invoices.
我正在尝试授权这些路线,因此只有以下用户:
在我的
AuthServiceProvider
中,我定义了以下政策:
protected $policies = [
Lease::class => LeasePolicy::class,
Invoice::class => InvoicePolicy::class,
];
在我的
LeaseController
中我定义了授权检查:
public function __construct()
{
$this->authorizeResource(Lease::class, 'lease');
}
LeasePolicy
看起来像这样:
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);
}
在我的
InvoiceController
中我定义了这一点:
public function __construct()
{
$this->authorizeResource(Invoice::class, 'invoice');
}
InvoicePolicy
看起来像这样:
/**
* 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);
}
在我的应用程序中,我有很多位于
/lease/{lease}/{model}
路线“下方”的路线,例如:
//Files
Route::resource('leases.files', FileController::class)
->only(['index'])
->shallow();
对于这些,我如何定义我的
Policies
,以便只有有权查看这些资源的用户才能访问?
据我在撰写此答案时所知,
authorizeResource
不能用于某些浅层嵌套方法(例如index
、create
和store
)。因此,您可以通过控制器助手在每个方法上调用 authorize
函数。
或者如果你仍然想使用authorizeResource
,你只能在一些浅层嵌套方法上手动调用
authorize
,如下例所示:
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);
...
}
}
顺便说一句,如果你想让InvoicePolicy
更简单,你也可以重用
LeasePolicy
,就像下面的代码:
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);
}
}
InvoicePolicy
将被注册为
Invoice
策略(请参阅策略发现)。
namespace App\Policies;
use App\Models\Invoice;
use App\Models\Lease;
use App\Models\User;
class InvoicePolicy
{
public function viewAny(User $user, Lease $lease): bool
{
//
}
public function view(User $user, Invoice $invoice, Lease $lease): bool
{
//
}
}
传递给 authorize
方法的数组的第一个元素决定将使用哪个模型。它可以是实例或类名(请参阅没有模型的方法和不需要模型的操作)。
namespace App\Http\Controllers;
use App\Models\Invoice;
use App\Models\Lease;
use App\Models\User;
class InvoiceController extends Controller
{
// leases/{lease}/invoices
public function index(Lease $lease)
{
$this->authorize('viewAny', [ Invoice::class, $lease ]);
//
}
// leases/{lease}/invoices/{invoice}
public function show(Lease $lease, Invoice $invoice)
{
$this->authorize('view', [ $invoice, $lease ]);
//
}
}