两种形式
Laravel 在 AuthServiceProvider
的 boot
方法里定义授权,有两种形式。
Gate::define('update articles', function ($user, $article) {
return $user->id == $article->user_id;
});
Gate::define('update articles', 'ArticlePolicy@update');
<?php
namespace App\Policies;
use App\User;
use App\Models\Article;
class ArticlePolicy
{
public function update(User $user, Article $article)
{
return $user->id == $article->author_id;
}
}
这两种形式的区别在于,授权逻辑是写在闭包里,还是 PHP 类方法里。闭包或方法最终都返回一个布尔值,true
表示有权限,false
表示没权限。
使用授权
有四种使用授权的方式:
- Gate 门面:
Gate::allows('update articles', $article)
和Gate::denies('update articles', $article)
。 - Controller:
$this->authorize('update articles', $article)
。 - Blade 模板:
@can('update articles', $article)
和@cannot('update articles', $article)
指令。 - User Model 实例:
$user->can('update articles', $article)
和$user->cannot('update articles', $article)
。
Policy
有些时候,直接用基于闭包的形式定义授权很不方便,特别是对某个资源(比如文章)基本的增、删、改、查操作。
Gate::define('view articles', function ($user, $article) {
return true;
});
Gate::define('create articles', function ($user) {
return true;
});
Gate::define('delete articles', function ($user, $article) {
return $user->id == $article->user_id;
});
Gate::define('update articles', function ($user, $article) {
return $user->id == $article->user_id;
});
如果再有一个视频资源的话,又得定义这四个方法了,这些方法堆在一起,很长。那么如果改成基于 PHP 类方法的形式,就好看一些了。
Gate::define('view articles', 'ArticlePolicy@view');
Gate::define('create articles', 'ArticlePolicy@create');
Gate::define('delete articles', 'ArticlePolicy@delete');
Gate::define('update articles', 'ArticlePolicy@update');
<?php
namespace App\Policies;
use App\User;
use App\Models\Article;
class ArticlePolicy
{
public function view(User $user, Article $article)
{
return true;
}
public function create(User $user)
{
return true;
}
public function delete(User $user, Article $article)
{
return $user->id == $article->author_id;
}
public function update(User $user, Article $article)
{
return $user->id == $article->author_id;
}
}
因为分类写了,所以定义授权的地方,看起来就比较清爽了。
为了能更加清爽地定义和使用授权,Laravel 引入了 Policy。在 AuthServiceProvider
的 policies
数组属性里添加授权映射关系即可!
/**
* The policy mappings for the application.
*
* @var array
*/
protected $policies = [
Article::class => ArticlePolicy::class,
];
所有与 Article Model 有关的授权逻辑都写在 ArticlePolicy
里,你可以用 make:policy
Artisan 命令生成他。Policy 只是在普通 PHP 类基础上添加了一个 HandlesAuthorization
trait。
<?php
namespace App\Policies;
use App\User;
use App\Models\Article;
use Illuminate\Auth\Access\HandlesAuthorization;
class ArticlePolicy
{
use HandlesAuthorization;
public function view(User $user, Article $article)
{
return true;
}
public function create(User $user)
{
return true;
}
public function delete(User $user, Article $article)
{
return $user->id == $article->author_id;
}
public function update(User $user, Article $article)
{
return $user->id == $article->author_id;
}
}
而且使用起来也非常方便。
$user->can('view', $article);
$user->can('create', Article::class);
$user->can('update', $article);
$user->can('delete', $article);
$article
是 Article Model 实例对象, Laravel 发现是对 Article Model 资源做授权判断,根据在 $policies
中定义的授权映射关系,自动找到 ArticlePolicy
下的 view
、create
、update
和 delete
方法。
当然,授权方法可自定义。比如我在 ArticlePolicy
下自定义了一个方法 xxx
,那么就可以直接用了。
$user->can('xxx', $article);
但有一个方法是特殊的 ——before
,在 Policy 中会在所有方法执行前调用,经常用到的地方就是处理管理员授权逻辑。
public function before($user, $ability)
{
if ($user->isSuperAdmin()) {
return true;
}
}
转自:https://learnku.com/articles/5479/introduce-laravel-authorization-mode-gate-and-policy