策略

到目前为止,所有访问控制都要求您手动将Eloquent模型与能力名称相关联。 您可能已经创建了一个名为visit-dashboard的功能,这个功能与特定的Eloquent模型无关,但您可能已经注意到我们的大部分示例都与某些事情有关 - 在大多数情况下, 行动的接受者的东西是一个Eloquent 模型。

授权策略是一种组织结构,可帮助您根据您控制访问的资源对授权逻辑进行分组。 它们可以轻松管理针对特定Eloquent模型(或其他PHP类)的行为定义授权规则,所有这些都在一个位置。

生成策略

Policies是一个PHP类,可以通过Artisan命令来生成。

php artisan make:policy ContactPolicy

生成后,需要进行注册。 AuthServiceProvider有一个$ policies属性,它是一个数组。 每个项的键是受保护资源的类名(几乎总是一个Eloquent类),值是策略类名。 例9-26看起来像这样。

Example 9-26. Registering policies in AuthServiceProvider
class AuthServiceProvider extends ServiceProvider {
    protected $policies = [
        Contact::class => ContactPolicy::class,
    ];

Artisan生成的策略类没有任何特殊属性或方法。但是你添加的每个方法现在都被映射为这个对象的键

策略自动发现

在运行Laravel5.8+的应用程序中,Laravel试图“猜测”策略与其相应模型之间的链接。例如,它会自动地将后策略应用到您的post模型。

如果需要自定义Laravel用于猜测此映射的逻辑,请查看策略文档

让我们定义一个更新方法看看如何工作的,如示例9-27

Example 9-27. A sample update() policy method
<?php
namespace App\Policies;
class ContactPolicy {
    public function update($user, $contact) {
        return $user->id == $contact->user_id; 
    }
}

请注意,此方法的内容与Gate定义中的内容完全相同。

不带实例的策略方法

如果你想定义一个策略方法关联到类而不是特定的实例-例如,“此用户是否可以创建联系人?“而不仅仅是”此用户能否查看此特定联系人?在Laravel 5.3中,你可以像对待普通方法一样对待它。在Laravel5.2中,创建该方法时,需要在其名称的末尾添加“any”

class ContactPolicy {
public function createAny($user) {
    return $user->canCreateContacts(); 
}

检查策略

如果为资源类型定义了策略,则Gate门户将使用第一个参数来确定要检查策略的方法。 如果运行Gate::allow('update',$ contact),它将检查ContactPolicy@update方法以进行授权。

这也适用于授权中间件以及用户模型检查和Blade检查,如例9-28所示。

Example 9-28. Checking authorization against a policy
// Gate
if (Gate::denies('update', $contact)) { 
    abort(403);
}
// Gate if you don't have an explicit instance
if (! Gate::check('create', Contact::class)) { 
    abort(403);
}
// User
if ($user->can('update', $contact)) { 
    // Do stuff
}
// Blade
@can('update', $contact) 
    // Show stuff
@endcan

另外,还有一个policy()辅助函数,允许您检索策略类和运行它的方法

if (policy($contact)->update($user, $contact)) { 
    // Do stuff
}

覆盖策略

就像普通的能力定义一样,策略可以定义一个before()方法,该方法允许你在调用被处理之前重写它(参见示例9-29)。

Example 9-29. Overriding policies with the before() method
public function before($user, $ability) {
    if ($user->isAdmin()) { 
        return true;
    } 
}

Last updated