I ended up using Laravel resources to accomplish this.
Here's an example (notice the can
array key):
class Ticket extends Resource
{
/**
* The "data" wrapper that should be applied.
*
* @var string
*/
public static $wrap = 'ticket';
/**
* Transform the resource into an array.
*
* @param \Illuminate\Http\Request $request
*
* @return array
*/
public function toArray($request)
{
return [
'id' => $this->id,
'answer_id' => $this->answer_id,
'summary' => $this->summary,
'description' => $this->description,
'creator' => $this->creator,
'created_at' => $this->created_at,
'updated_at' => $this->updated_at,
'reported_at' => $this->reported_at,
'closed_at' => $this->closed_at,
'closed' => $this->closed,
'answered' => $this->answered,
'can' => $this->permissions(),
];
}
/**
* Returns the permissions of the resource.
*
* @return array
*/
protected function permissions()
{
return [
'update' => Gate::allows('update', $this->resource),
'delete' => Gate::allows('delete', $this->resource),
'open' => Gate::allows('open', $this->resource),
];
}
}
This allowed me to control access on the front-end using simple boolean logic in Vue templates, rather than duplicating actual permission logic on the front-end as well:
<router-link v-if="ticket.can.update" :to="{name:'tickets.edit', params: {ticketId: ticket.id}}" class="btn btn-sm btn-secondary">
<i class="fa fa-edit"></i> Edit
</router-link>
Also, I used Laravel resource collections to be able to apply permissions if the user is able to create a resource:
class TicketCollection extends ResourceCollection
{
/**
* The "data" wrapper that should be applied.
*
* @var string
*/
public static $wrap = 'tickets';
/**
* Get any additional data that should be returned with the resource array.
*
* @param \Illuminate\Http\Request $request
*
* @return array
*/
public function with($request)
{
return [
'can' => [
'create' => Gate::allows('create', Ticket::class),
],
];
}
}
Then in my API controller:
public function index()
{
$tickets = Ticket::paginate(25);
return new TicketCollection($tickets);
}
public function show(Ticket $ticket)
{
$ticket->load('media');
return new TicketResource($ticket);
}
This allowed me to validate if the currently authenticated user has access to be able to create the resource that is being listed, since we won't have an actual resource to validate on, we can do this on the returned collection since it relates to it entirely.
Implementing this pattern seemed to me the simplest way of managing authorization without duplicating the actual authorizing logic throughout my Vue app and using blade to inject permissions into components individually.
如果您的嵌套组件也需要权限,那么将权限注入组件最终会给我带来问题,因为这样您就需要将子组件的权限传递给父组件才能验证它们.
For nested permissions, you can return sub-resources from your parent resource for relationships that also include a can permissions array, so you can easily loop through these using Vue and use simple logic for determining the users access on those as well.
这种方法也很有好处,因为我可以通过服务器端缓存每个用户对不经常更改的资源的权限.