Laravel 用户授权:设置授权规则 1 个改进

假设我们有一个 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 ,那么授权会在这个策略中失败。

本文为 Wiki 文章,邀您参与纠错、纰漏和优化
讨论数量: 0
(= ̄ω ̄=)··· 暂无内容!

讨论应以学习和精进为目的。请勿发布不友善或者负能量的内容,与人为善,比聪明更重要!