Php Laravel用户能力
在Laravel中,您可以轻松地连接到它们,然后根据用户的请求执行不同的操作:Php Laravel用户能力,php,laravel,laravel-5.1,Php,Laravel,Laravel 5.1,在Laravel中,您可以轻松地连接到它们,然后根据用户的请求执行不同的操作: $gate->define('update-post', function ($user, $post) { return $user->id === $post->user_id; }); 但是几乎我所有定义的能力都包含这一部分$user->id====$model->user\u id。我不喜欢它,因为它是一种反复重复的条件,我认为它可能更抽象 我定义的大多数能力都是根据更新/删除记录
$gate->define('update-post', function ($user, $post) {
return $user->id === $post->user_id;
});
但是几乎我所有定义的能力都包含这一部分$user->id====$model->user\u id
。我不喜欢它,因为它是一种反复重复的条件,我认为它可能更抽象
我定义的大多数能力都是根据更新/删除记录来定义的,因此,如果我可以将全局条件应用于所有记录,或者如果可以有一个组能力定义,这与我们在路由中所做的类似,那就更好了
有什么解决办法吗?我真的很喜欢干的。我想你可以用中间产品 只需制作一个管理中间件,并在routes和routes组中使用它 您的项目上没有安全漏洞(删除、创建和…操作),因为Laravel有csrf令牌 您也可以使用函数 还有一个重要的提示: 如果您没有在策略类上定义相应的函数并在控制器上调用它
$this->authorize($post)
,则将抛出未经授权的操作
错误,除非before()
方法返回
strue
例如,在Dashboard\PostsController
上调用$this->authorize
:
public function edit($id)
{
$post = Post::find($id)->first();
$this->authorize($post);
return view('dashboard.post')->with(compact('post'));
}
如果我们定义了一个后策略类:
class PostPolicy
{
use HandlesAuthorization;
public function before($user, $ability)
{
return $user->is_admin;
}
}
如果用户是管理员,他/她可以编辑帖子,因为我们在before()中返回edtrue
,
方法,尽管没有同名的方法(与PostsController中的edit
方法相同)
事实上,Laravel将检查策略类
上的before方法方法。如果在返回之前,的null
将检查控制器方法上是否有同名的对应方法,如果未找到此方法,则用户无法执行操作
谢谢拉威尔为我们干杯!♥ 将此函数添加到AuthServiceProvider
public function defineAbilities(array $abilities, $gate)
{
foreach($abilities as $name => $model){
$gate->define($name, function ($user, $model){
return $user->id === ${$model}->user_id;
});
}
}
然后是内部引导方法
$this->defineAbilities(['ability1' => 'model1', 'ability2' => 'model2'], $gate);
我仔细检查了你的问题,但我没有找到“简单”的方法
相反,我可能会这样做:
<?php
namespace App\Policies;
use App\User;
use App\Post;
trait CheckOwnership {
protected function checkOwnership($user, $model) {
$owned = $user->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;
}
}
}
您可以定义另一个函数并在匿名函数中调用它。这将允许您在一个中心位置拥有常用代码,同时仍然允许任何特定于资源的逻辑
将此函数添加到AuthServiceProvider
类:
public function userCheck(User $user, $target)
{
// do the user id check
$result = isset($target->user_id) && isset($user) && $user->id === $target->user_id;
return $result;
}
您的代码,已修改:
$gate->define('update-post', function ($user, $post) {
// call the function
$result = $this->userCheck($user, $post);
// do some kind of 'update-post' specific check
return $result/* && some_bool_statement*/;
});
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
中执行此操作(假设它正在扩展illighted\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();
});
});
}
这样,您可以使用definethownership()
方法而不是define()
来定义能力。对于不需要所有权验证的能力,您仍然可以使用define()
。还有第三个参数definethownership()
接受它,即$foreignUserIdKey
;用于模型具有不同用户id字段的情况
注意:我在运行中编写了代码,没有尝试,它可能有错误,但你明白了。谢谢,但我没有说我的能力只返回一个$user->id===$model->user\u id
结果。我说它有这个部分,所以它可能像$user->id==$post->user\u id&$post->status==0
。谢谢你,蓝色。这是一个nice和clean方法,但我能从中得到的只是一个错误,无法解决的依赖项解析[Parameter#1[callable$userResolver]]类中的illights\Auth\Access\Gate
我不确定,但我认为自定义重写的registerAccessGate()
方法未被调用。好的,您的AuthServiceProvider
是否扩展了Laravel的AuthServiceProvider
?是否使用自定义的register()
方法?另一种注册方法是将函数重命名为其他函数,然后在parent::register()之后调用该函数
在您的register()
方法中。完整的异常堆栈将非常有用(忽略任何敏感信息)。您可以使用粘贴箱并将其链接到此处。默认情况下,MyAuthServiceProvider
类扩展了Illumb\Foundation\Support\Providers\AuthServiceProvider
。我没有使用自定义的register()
方法在我的AuthServiceProvider
中,但正如您提供的那样,我编写了一个public register();
并调用了parent::register()
和重命名的registerAccessGate()形式
方法。但我收到了与我上面评论的错误完全相同的错误。我粘贴了相关的laravel.log部分。Sliphon我遇到了一件奇怪的事情:define
的第二个参数应该是callable
类型。有什么解决方法吗?虹吸似乎是$user
和$post
作为userCheck()
的第一个和第二个参数不会传递给函数:未定义变量:user
如果您可以修改您的答案以获得一个有效的解决方案,那么我将毫不犹豫地奖励另一个奖励。我已将我的答案更新为更优雅的答案。似乎闭包会使代码变得不必要的复杂。您需要做的是简单地使用一个简单的助手函数来整合逻辑。