在Laravel中,您可以轻松定义功能,然后在用户请求中挂钩,以执行不同的操作:
$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的不同字段时,用于该情况.
注意:我在运行中编写了代码并没有尝试,它可能有错误,但你明白了.
我检查了你的问题很多,但我发现没有"简单"的方法.
相反,我可能会这样做:
id === $model->user_id; if ($owned === false) throw new NotOwnedException; } } class PostPolicy { use CheckOwnership; public function update(User $user, Post $post) { try { $this->checkOwnership($user, $post); //continue other checks } catch (NotOwnedException $ex) { return false; } } }