在 Laravel 中你可以很容易地 define abilities然后在用户请求执行不同的操作时挂接到它们:
$gate->define('update-post', function ($user, $post) {
return $user->id === $post->user_id;
});
但几乎所有我定义的能力都有这部分 $user->id === $model->user_id
在里面。我不喜欢它,因为它是一种一遍又一遍地重复我认为可能更抽象的条件。
我定义的大部分能力都是根据更新/删除记录,所以如果我可以将全局条件应用于所有这些,或者如果可以有一个组能力定义我们在做什么会更好路由。
有什么解决方法吗?我真的很喜欢干。
最佳答案
Laravel 中的一切都是可扩展的,这就是它的服务提供者的力量。
您可以将 Gate
对象扩展为 MyCustomGate
对象,并在该对象中执行您想要的任何操作。这是一个例子:
MyCustomGate.php
class MyCustomGate extends \Illuminate\Auth\Access\Gate
{
protected $hasOwnershipVerification = [];
/**
* Define a new ability.
*
* @param string $ability
* @param callable|string $callback
* @return $this
*
* @throws \InvalidArgumentException
*/
public function defineWithOwnership($ability, $callback, $foreignUserIdKey = "user_id")
{
// We will add this
$this->hasOwnershipVerification[$ability] = $foreignUserIdKey;
return $this->define($ability, $callback);
}
/**
* Resolve and call the appropriate authorization callback.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $ability
* @param array $arguments
* @return bool
*/
protected function callAuthCallback($user, $ability, array $arguments)
{
$callback = $this->resolveAuthCallback(
$user, $ability, $arguments
);
// We will assume that the model is ALWAYS the first key
$model = is_array($arguments) ? $arguments[0] : $arguments;
return $this->checkDirectOwnership($ability, $user, $model) && call_user_func_array(
$callback, array_merge([$user], $arguments)
);
}
/**
* Check if the user owns a model.
*
* @param string $ability
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param \Illuminate\Database\Eloquent\Model $model
* @return bool
*/
protected function checkDirectOwnership($ability, $user, $model)
{
if(!isset($this->hasOwnershipVerification[$ability])) {
return true
}
$userIdKey = $this->hasOwnershipVerification[$ability];
// getAuthIdentifier() is just ->id, but it's better in case the pk of a user is different that id
return $user->getAuthIdentifier() == $model->{$userIdKey};
}
}
然后,你必须告诉 Laravel 使用你的门而不是默认门。您可以在您的 AuthServiceProvider
中执行此操作(假设它正在扩展 Illuminate\Auth\AuthServiceProvider
,只需添加以下方法。
AuthServiceProvider
/**
* Register the access gate service.
*
* @return void
*/
protected function registerAccessGate()
{
$this->app->singleton(\Illuminate\Contracts\Auth\Access\Gate::class, function ($app) {
return new MyCustomGate($app, function () use ($app) {
return $app['auth']->user();
});
});
}
这样,您可以使用 defineWithOwnership()
方法而不是 define()
来定义能力。您仍然可以将 define()
用于不需要所有权验证的功能。 defineWithOwnership()
接受的第三个参数是 $foreignUserIdKey
;这用于模型具有不同的用户 ID 字段的情况。
注意:我是即时编写的代码,没有尝试,可能有错误,但你明白了。
关于php - Laravel 用户能力,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/34375042/