Laravel 用户授权:设置授权规则
假设我们有一个 Post 模型表示博客,以及还有一个默认的 User 模型表示用户。我们可以通过下面的方法来设置授权规则。
创建授权策略
策略是在特定模型或者资源中组织授权逻辑的类。例如,你的应用是一个博客,那么你在创建或者更新博客的时候,你可能会有一个 Post
模型和一个对应的 PostPolicy
来授权用户动作。
你可以使用 artisan 命令
artisan command 中的 make:policy
artisan command 命令来生成策略。 生成的策略将放置在 app/Policies
目录中。如果在你的应用中不存在这个目录,那么 Laravel 将会为你自动生成:
php artisan make:policy PostPolicy
make:policy
命令会生成一个空的策略类。如果你想生成的类包含基本的 「CRUD」策略方法,你可以在执行命令的时候指定 --model
这个选项:
注册策略
一旦策略存在,它就需要进行注册。新的 Laravel 应用中包含的 AuthServiceProvider
有一个 policies
属性,可以将各种模型对应到它们的策略中。注册一个策略将引导 Laravel 在授权动作访问指定模型的时候使用哪种策略:
<?php
namespace App\Providers;
use App\Post;
use App\Policies\PostPolicy;
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
class AuthServiceProvider extends ServiceProvider
{
/**
* 应用的策略映射。
*
* @var array
*/
protected $policies = [
Post::class => PostPolicy::class,
];
/**
* 注册任意应用认证、应用授权服务
*
* @return void
*/
public function boot()
{
$this->registerPolicies();
//
}
}
策略自动发现
只要模型和策略遵循标准的 Laravel 命名约定,Laravel 就可以自动发现策略,而不是手动注册模型策略。具体而言,策略必须位于包含模型的目录下的 Policies
目录中。因此,例如模型可以放在 app
目录中,而策略可以放在 app/Policies
目录中。此外,策略名称必须与模型名称匹配,并具有 Policy
后缀。因此,User
模型将对应于 UserPolicy
类。
如果您想提供自己的策略发现逻辑,可以使用 Gate :: guessPolicyNamesUsing
方法注册自定义回调。通常,应该从应用程序的 AuthServiceProvider
的 boot
方法调用此方法:
use Illuminate\Support\Facades\Gate;
Gate::guessPolicyNamesUsing(function ($modelClass) {
// return policy class name...
});
注意:在
AuthServiceProvider
中显式映射的任何策略都将优先于自动发现策略。
编写策略
策略方法
一旦授权策略被注册,你就可以为授权过后的每个动作添加方法。比如,我们在 PostPolicy
中定义一个 update
方法,它会判断指定的 User
是否可以更新指定的 Post
实例。
update
方法接收 User
和 Post
实例作为参数,并且应该返回 true
或者 false
来表明用户是否被授权更新指定的 Post
。所以在这个例子中,我们需要判断用户的 id
是否和 post 中的 user_id
匹配。
<?php
namespace App\Policies;
use App\User;
use App\Post;
class PostPolicy
{
/**
* 判断该方法能否被用户操作。
*
* @param \App\User $user
* @param \App\Post $post
* @return bool
*/
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
你可以继续为这个授权策略定义额外的方法。比如,你可以定义 view
或者 delete
方法来授权 Post
的多种行为,还可以为自定义的策略方法起一个你自己喜欢的名字。
不包含模型方法
一些策略方法只接收当前认证通过的用户作为参数,而不用传入与授权相关的模型实例。最常见的应用场景就是授权 create
动作。比如,如果你正在创建一篇博客,你可能希望先检查一下当前用户是否有权限创建它。
当定义一个不需要传入模型实例的策略方法时,比如 create
方法,它就是不接收模型实例作为参数。你应该定义这个方法只接收授权过的用户作为参数。
/**
* 判断用户是否可以创建请求。
*
* @param \App\User $user
* @return bool
*/
public function create(User $user)
{
//
}
访客用户
默认情况下,如果传入的 HTTP 请求不是经过身份验证的用户发起的,那么所有的 gates 和策略都会自动返回 false
。 然而,你可以允许这些授权检查通过声明一个『可选的』类型提示或为用户参数定义提供 null
默认值,从而传递到你的 gates 和策略中:
<?php
namespace App\Policies;
use App\User;
use App\Post;
class PostPolicy
{
/**
* 判断用户是否能更新指定帖子。
*
* @param \App\User $user
* @param \App\Post $post
* @return bool
*/
public function update(?User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
策略过滤器
对特定用户,你可能希望通过指定的策略授权所有动作。 要达到这个目的,可以在策略中定义一个 before
方法。 before
方法会在策略中其它所有方法之前执行,这样提供了一种方式来授权动作而不是指定的策略方法来执行判断。这个功能最常见的场景是授权应用的管理员可以访问所有动作:
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
如果你想拒绝某个用户所有的授权,你应当在 before
方法中返回 false
。如果返回值是 null
,那么授权会在这个策略中失败。
推荐文章: