【问题标题】:Allow edit of Model based on a set permission as well as Model's property value in Laravel允许根据设置的权限以及模型在 Laravel 中的属性值编辑模型
【发布时间】:2020-06-26 10:42:35
【问题描述】:

我有一个位置模型,它包含两个属性:ID 和名称。

为了编辑这个模型,我设置了这条路线:

Route::get('administration/location/{location}/edit', 'LocationController@edit')->name('location.edit');

我设置了非常简单的权限:在AuthServiceProvider 我正在检查boot 方法如下

Gate::before(function ($user, $permission) {
    if ($user->permissions->pluck('name')->contains($permission)) {
        return true;
    }
});

permission 是一个模型,其中包含一个 ID 和一个名称,通过 permission_user 表映射。

我已设置以下权限:

  • edit_los_angeles
  • edit_new_york
  • edit_boston
  • plenty_of_other_permissions_not_related_to_location

在所有这些杂乱无章之后,我的实际问题:

如何将这些权限与编辑位置相关联?

我面临的问题是,不允许给定用户编辑所有位置,但可能只允许编辑一个位置。只有拥有edit_los_angeles 权限的用户才能编辑名称为Los AngelesLocation
所以我不能把它组合成一个权限,比如edit_location,然后把它添加到我的路由->middleware('can:edit_location')

相反,我想我需要这样的东西:

Route::get('administration/location/{location}/edit', 'LocationController@edit')->name('location.edit')->middleware('can:edit_los_angeles');
Route::get('administration/location/{location}/edit', 'LocationController@edit')->name('location.edit')->middleware('can:edit_new_york');
Route::get('administration/location/{location}/edit', 'LocationController@edit')->name('location.edit')->middleware('can:edit_boston');

...显然这行不通。

您会采取什么方法来解决这个难题? :-)
也许我做错了什么,有更好的 Laravel-Way 这样做吗?

非常感谢您提前提供的帮助!

我正在使用 Laravel 6.0 :-)

【问题讨论】:

  • 我猜位置是模型?
  • 是的,位置是一个模型:-)
  • 我觉得有一个更通用的解决方案今晚会写一个解决方案。
  • 感谢@mrhn 期待它:-)
  • 位置和权限之间是否有任何绑定,或者您可以从名称中派生出它们吗?

标签: php laravel laravel-6


【解决方案1】:

我的工作方法有两个假设,在控制器中使用模型绑定(无论如何你都应该这样做)。其次,位置和它所需的权限之间需要有关系,类似于您建议的 slug。

你的控制器函数看起来像这样。添加 FormRequest 是执行此逻辑的好方法。

class LocationController {
     public function edit(EditLocationRequest $request, Location $location) { // implicit model binding
         ...
     }
}

为了方便使用,我也会制定一个政策。

class LocationPolicy
{
    public function edit(User $user, Location $location) {
        return $user->permissions->pluck('name')
            ->contains($location->permission_slug); // assuming we have a binding
    }
}

记得在AuthServiceProvider.php注册政策。

protected $policies = [
    Location::class => LocationPolicy::class,
];

现在在您的表单请求中使用授权方法中的策略。从这里您处于请求上下文中,您可以访问$this->user() 上的用户,并且您可以访问与其名称绑定模型的所有模型,例如$this->location

class EditLocationRequest
{
    public function authorize(): bool
    {
        return $this->user()->can('edit', $this->location);
    }
}

现在您应该只能有一个路由定义。

Route::get('administration/location/{location}/edit', 'LocationController@edit')->name('location.edit');

编辑

如果您使用特征 AuthorizesRequests,则无需表单请求,您可以执行以下操作。这将抛出 AuthorizationException 失败。

use AuthorizesRequests;

public function edit() {
    $this->authorize('edit', $location);
}

【讨论】:

  • 我知道这与你最初对门的想法有点远,但我就是这样做的,在这里你不需要多个路线定义
  • 哇,我从这篇文章中学到了很多东西!非常感谢@mrhn!我明天试试这个。祝你周日休息愉快:-)
  • 您会建议使用php artisan make:request 创建表单请求以创建EditLocationRequest 还是应该将其命名为LocationRequest?不确定正确的约定是什么。
  • 哇,没关系。它已经做到了。非常感谢您提供了如何使用策略和表单请求的绝佳示例!非常感谢!
  • 没问题,伙计,我认为这是实现它的一种非常干净的方法
【解决方案2】:

如果您有基于位置关系的要求,那么您需要在数据中捕获该关系。一个很好的起点是添加特定于这些编辑权限的数据透视表。考虑一个表location_permissions,其中包含user_idlocation_id。然后,您可以修改或添加权限中间件,以便在您拥有特定用户和位置后检查此表中的记录。

编辑:回答关于中间件实现的问题,

通过这个新的数据透视表定义用户模型与位置的关系可能会解决实现的关键。

我建议然后添加一个额外的方法,该方法使用新的locations 关系到模型的行

public function canEditLocation(Location $location): bool { 

   return $this->locations
               ->where('location_id', '=', $location->id)
               ->count() > 0; 
    }

而实际的中间件是这样的:

public function handle($request, Closure $next, $location)
    {
        if (! $request->user()->canEditLocation($location)) {
            \\handle failed permission as appropriate here.
        }

        return $next($request);
    }

我的中间件参数知识很生疏,但我相信https://laravel.com/docs/master/middleware#middleware-parameters定义的正确

【讨论】:

  • 添加的权限中间件会是什么样子? :-)
  • 非常感谢!我会尝试这种方法 :-) 你会在哪里添加 canEditLocation 方法?到 Location 模型本身?
  • 我认为直接将其添加到模型中是有意义的,是的。很高兴听到这有帮助!
  • 太棒了!再次感谢您的帮助:-)
猜你喜欢
  • 1970-01-01
  • 2020-02-07
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2017-03-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
相关资源
最近更新 更多