我不确定以前是如何处理这个问题的,但我该如何使用VueJs并在Vue模板中授权操作呢?

If I'm using Laravel's blade, this is easy (using @can directive), but there's no documentation or any way to perform this in Vue after searching for hours on Google.

Now, I know I can simply load the users permissions into an array / JSON object inside the view, but there seems to be no way of displaying / hiding actions in Vue templates using Laravel's gate methods to determine if the user is allowed to perform the action on a specific record.

For example, there's a list of comments, but the user must own the comment to be able to see the 'edit' button.

问题是,如果我在Vue中实现这个逻辑,我将在整个后端和前端复制授权逻辑.

使用Laravel的策略,我能够执行特定操作的复杂授权.但我对如何在Vue实施这项政策感到困惑.

还有更复杂的场景,例如,如果一个拥有admin个角色的用户正在浏览 comments ,即使他们不拥有该 comments ,他们也应该能够对其进行编辑.

有没有人对这种情况有什么建议?

EDIT:

现在,我可以向我的模型添加一个属性访问器,例如:

Model:

class Comment extends Model
{
    protected $appends = ['can_update'];

    public function getCanUpdateAttribute()
    {
        return Gate::allows('update', $this);
    }
}

Vue:

<button v-if="comment.can_update">Edit</button>

But this seems like I'm again duplicating logic that already exists inside my policies.

推荐答案

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.

这种方法也很有好处,因为我可以通过服务器端缓存每个用户对不经常更改的资源的权限.

Laravel相关问答推荐

为什么在Blade 文件中输出用户通知时出现错误?

子目录中具有Vue实例的Laravel不起作用

用Laravel Filament创建变形组件

Laravel 数据未传递到下拉框

Laravel 9 上的数组差异助手

仅针对字母的 laravel 验证规则

如何在 vue 模板中引用 laravel csrf 字段

Laravel 5.1 - 如何在进度条上设置消息

调用未定义函数 Illuminate\Encryption\openssl_decrypt()

Laravel Request::input 调用未定义的方法

Laravel 查询构建器 - 如何按别名分组,或进行原始 groupBy

Laravel 4:读取由 javascript 设置的 cookie

Laravel:每当我返回一个模型时,总是返回一个与它的关系

使用 vue-router 更改路由时中止所有 Axios 请求

在 Laravel 5.4 中将中间件应用于除 `setup/*` 之外的所有路由

如何在 Laravel 5 中验证当前、新密码和新密码确认?

Laravel 模型:模型属性在哪里?

Laravel 验证存在于不存在的地方

Laravel 5如何获取路由动作名称?

在laravel中删除确认