[英]Laravel resource policy always false
我试图允许用户在 Laravel 5.4 中查看他们自己的个人资料。
用户策略.php
public function view(User $authUser, $user)
{
return true;
}
在 AuthServiceProvider.php 中注册的策略
protected $policies = [
App\Task::class => App\Policies\TaskPolicy::class,
App\User::class => App\Policies\UserPolicy::class
];
路线
Route::group(['middleware' => 'auth'], function() {
Route::resource('user', 'UserController');
} );
刀片模板
@can ( 'view', $user )
// yes
@else
// no
@endcan
用户控制器.php
public function profile()
{
return $this->show(Auth::user()->id);
}
public function show($id)
{
$user = User::find($id);
return view('user.show', array( 'user'=>$user,'data'=>$this->data ) );
}
返回总是“假”。 从控制器调用策略也是如此。 我哪里出错了?
回答我自己的问题感觉很奇怪,但是当我遇到没有跟进的问题时,我讨厌它。
所以经过仔细检查后发现,如果我从构造函数中删除authorizeResource :
public function __construct()
{
$this->authorizeResource(User::class);
}
并检查控制器功能中的授权:
$this->authorize('view',$user);
一切正常。 当我在策略函数中添加$user
作为参数时,我一定错过了这一部分。 所以要查看的用户永远不会传入authorizeResource
方法。
感谢大家花时间帮助我。
当你添加
public function __construct()
{
$this->authorizeResource(User::class);
}
对于您的控制器,您必须编辑所有函数签名以将其与类匹配,例如您的显示签名必须从public function show($id)
更改为public function show(User $user)
之后它应该工作
对于用户查看他们自己的个人资料,这里只是一种不同的方法。
首先,我将为此创建一条路线
Route::group(['middleware' => 'auth'], function() {
Route::get('profile', 'UserController@profile');
});
然后在profile
功能中我做
public function profile()
{
$user = Auth::user();
return view('profile', compact('user'));
}
这样,用户自动只查看他们自己的个人资料。
现在,如果您想允许某些用户查看其他用户的个人资料,则可以使用 Policy。 为什么? 因为我认为用户应该始终能够查看他们自己的个人资料。 但并非所有用户都应该查看其他用户的个人资料。
解决方案:
将第二个参数从@can( 'view', $user )
更改为@can( 'view', $subject )
,它会找到工作。
为什么:
因为你做错了。
public function view(User $user, $subject){
return true;
}
仔细查看策略视图方法,第一个参数是经过authenticated user
或current user
,第二个参数是$subject
,因为策略围绕模型组织授权逻辑。
策略是围绕特定模型或资源组织授权逻辑的类。 例如,如果您的应用程序是一个博客,您可能有一个 Post 模型和一个相应的 PostPolicy 来授权用户操作,例如创建或更新帖子。
如果你想更深入地了解它。
https://github.com/laravel/framework/blob/5.3/src/Illuminate/Auth/Access/Gate.php#L353
/**
* Resolve the callback for a policy check.
*
* @param \Illuminate\Contracts\Auth\Authenticatable $user
* @param string $ability
* @param array $arguments
* @return callable
*/
protected function resolvePolicyCallback($user, $ability, array $arguments)
{
return function () use ($user, $ability, $arguments) {
$instance = $this->getPolicyFor($arguments[0]);
// If we receive a non-null result from the before method, we will return it
// as the final result. This will allow developers to override the checks
// in the policy to return a result for all rules defined in the class.
if (method_exists($instance, 'before')) {
if (! is_null($result = $instance->before($user, $ability, ...$arguments))) {
return $result;
}
}
if (strpos($ability, '-') !== false) {
$ability = Str::camel($ability);
}
// If the first argument is a string, that means they are passing a class name
// to the policy. We will remove the first argument from this argument list
// because the policy already knows what type of models it can authorize.
if (isset($arguments[0]) && is_string($arguments[0])) {
array_shift($arguments);
}
if (! is_callable([$instance, $ability])) {
return false;
}
return $instance->{$ability}($user, ...$arguments);
};
}
请参阅最后一行,它使用 $user 调用方法,并传递了 $argument(在我们的示例中为 Model )。
可以使用 authorizeResource 中的 options 参数来转义一个或多个策略方法,除了:
public function __construct()
{
$this->authorizeResource(User::class, 'user', ['except' => ['view']]);
}
这应该在 Laravel 的文档中,但事实并非如此。 我发现这只是猜测。 我认为这种方式是一种更好的方法,因此,通过删除construct
authorizeResource
方法,有必要为每个资源操作实现authorization
方法以保护控制器。
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.