目录
1、简介
2、定义权限(Abilities)
3、检查权限(Abilities)
通过 Gate 门面
通过 User模型
在  Blade  模板引擎中检查
在表单请求中检查
4、策略类(Policies)
创建策略类
编写策略类
检查策略
5、 控制器授权
首页 后端开发 php教程 [ Laravel 5.2 文档 ] 服务 -- 用户授权

[ Laravel 5.2 文档 ] 服务 -- 用户授权

Jun 23, 2016 pm 01:18 PM

1、简介

除了提供开箱即用的认证服务之外,Laravel还提供了一个简单的方式来管理授权逻辑以便控制对资源的访问权限。在 Laravel 中,有多种方法和辅助函数来协助你管理授权逻辑,本文档将会一一覆盖这些方法。

2、定义权限(Abilities)

判断用户是否有权限执行给定动作的最简单方式就是使用 Illuminate\Auth\Access\Gate类来定义一个“权限”。我们在 AuthServiceProvider中定义所有权限,例如,我们来定义一个接收当前 User和 Post 模型的 update-post权限,在该权限中,我们判断用户 id是否和文章的 user_id匹配:

<?phpnamespace App\Providers;use Illuminate\Contracts\Auth\Access\Gate as GateContract;use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;class AuthServiceProvider extends ServiceProvider{    /**     * 注册应用所有的认证/授权服务.     *     * @param  \Illuminate\Contracts\Auth\Access\Gate  $gate     * @return void     */    public function boot(GateContract $gate)    {        parent::registerPolicies($gate);        $gate->define('update-post', function ($user, $post) {            return $user->id === $post->user_id;        });    }}
登录后复制

注意我们并没有检查给定 $user是否为 NULL,当用户未经过登录认证或者用户没有通过 forUser方法指定, Gate会自动为所有权限返回 false。

基于类的权限

除了注册授权回调闭包之外,还可以通过传递包含权限类名和类方法的方式来注册权限方法,当需要的时候,该类会通过服务容器进行解析:

$gate->define('update-post', 'PostPolicy@update');
登录后复制

拦截认证检查

有时候,你可能希望对指定用户授予所有权限,在这种场景中,需要使用 before方法定义一个在所有其他授权检查之前运行的回调:

$gate->before(function ($user, $ability) {    if ($user->isSuperAdmin()) {        return true;    }});
登录后复制
登录后复制

如果 before回调返回一个非空结果,那么该结果则会被当做检查的结果。

你也可以使用 after方法定义一个在所有其他授权检查之后运行的回调,所不同的是,在 after回调中你不能编辑授权检查的结果:

$gate->after(function ($user, $ability, $result, $arguments) {    //});
登录后复制

3、检查权限(Abilities)

通过 Gate 门面

权限定义好之后,可以使用多种方式来“检查”。首先,可以使用 Gate 门面的 check, allows, 或者 denies方法。所有这些方法都接收权限名和传递给该权限回调的参数作为参数。你不需要传递当前用户到这些方法,因为 Gate会自动附加当前用户到传递给回调的参数,因此,当检查我们之前定义的 update-post权限时,我们只需要传递一个 Post实例到 denies方法:

<?phpnamespace App\Http\Controllers;use Gate;use App\User;use App\Post;use App\Http\Controllers\Controller;class PostController extends Controller{    /**     * 更新给定文章     *     * @param  int  $id     * @return Response     */    public function update($id)    {        $post = Post::findOrFail($id);        if (Gate::denies('update-post', $post)) {            abort(403);        }        // 更新文章...    }}
登录后复制

当然, allows方法和 denies方法是相对的,如果动作被授权会返回 true, check方法是 allows方法的别名。

为指定用户检查权限

如果你想要使用 Gate门面判断非当前用户是否有权限,可以使用 forUser方法:

if (Gate::forUser($user)->allows('update-post', $post)) {    //}
登录后复制

传递多个参数

当然,权限回调还可以接收多个参数:

Gate::define('delete-comment', function ($user, $post, $comment) {    //});
登录后复制

如果权限需要多个参数,简单传递参数数组到 Gate方法:

if (Gate::allows('delete-comment', [$post, $comment])) {    //}
登录后复制

通过 User模型

还可以通过 User模型实例来检查权限。默认情况下,Laravel 的 App\User模型使用一个 Authorizabletrait来提供两种方法: can和 cannot。这两个方法的功能和 Gate门面上的 allows和 denies方法类似。因此,使用我们前面的例子,可以修改代码如下:

<?phpnamespace App\Http\Controllers;use App\Post;use Illuminate\Http\Request;use App\Http\Controllers\Controller;class PostController extends Controller{    /**     * 更新给定文章     *     * @param  \Illuminate\Http\Request  $request     * @param  int  $id     * @return Response     */    public function update(Request $request, $id)    {        $post = Post::findOrFail($id);        if ($request->user()->cannot('update-post', $post)) {            abort(403);        }        // 更新文章...    }}
登录后复制

当然, can方法和 cannot方法相反:

if ($request->user()->can('update-post', $post)) {    // 更新文章...}
登录后复制

Blade 模板引擎中检查

为了方便,Laravel 提供了 Blade 指令 @can来快速检查当前用户是否有指定权限。例如:

<a href="/post/{{ $post->id }}">View Post</a>@can('update-post', $post)    <a href="/post/{{ $post->id }}/edit">Edit Post</a>@endcan
登录后复制

你还可以将 @can指令和 @else指令联合起来使用:

@can('update-post', $post)    <!-- The Current User Can Update The Post -->@else    <!-- The Current User Can't Update The Post -->@endcan
登录后复制

在表单请求中检查

你还可以选择在表单请求的 authorize方法中使用 Gate定义的权限。例如:

/** * 判断请求用户是否经过授权 * * @return bool */public function authorize(){    $postId = $this->route('post');    return Gate::allows('update', Post::findOrFail($postId));}
登录后复制

4、策略类(Policies)

创建策略类

由于在 AuthServiceProvider中定义所有的授权逻辑将会变得越来越臃肿笨重,尤其是在大型应用中,所以 Laravel 允许你将授权逻辑分割到多个“策略”类中,策略类是原生的PHP类,基于授权资源对授权逻辑进行分组。

首先,让我们生成一个策略类来管理对 Post模型的授权,你可以使用 Artisan 命令 make:policy来生成该策略类。生成的策略类位于 app/Policies目录:

php artisan make:policy PostPolicy
登录后复制

注册策略类

策略类生成后我们需要将其注册到 Gate类。 AuthServiceProvider包含了一个 policies属性来映射实体及管理该实体的策略类。因此,我们指定 Post模型的策略类是 PostPolicy:

<?phpnamespace App\Providers;use App\Post;use App\Policies\PostPolicy;use Illuminate\Contracts\Auth\Access\Gate as GateContract;use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;class AuthServiceProvider extends ServiceProvider{    /**     * 应用的策略映射     *     * @var array     */    protected $policies = [        Post::class => PostPolicy::class,    ];    /**     * 注册所有应用认证/授权服务     *     * @param \Illuminate\Contracts\Auth\Access\Gate $gate     * @return void     */    public function boot(GateContract $gate)    {        $this->registerPolicies($gate);    }}
登录后复制

编写策略类

策略类生成和注册后,我们可以为授权的每个权限添加方法。例如,我们在 PostPolicy中定义一个 update方法,该方法判断给定 User是否可以更新某个 Post:

<?phpnamespace 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;    }}
登录后复制

你可以继续在策略类中为授权的权限定义更多需要的方法,例如,你可以定义 show, destroy, 或者 addComment方法来认证多个 Post动作。

注意:所有策略类都通过服务容器进行解析,这意味着你可以在策略类的构造函数中类型提示任何依赖,它们将会自动被注入。

拦截所有检查

有时候,你可能希望对指定用户授予所有权限,在这种场景中,需要使用 before方法定义一个在所有其他授权检查之前运行的回调:

$gate->before(function ($user, $ability) {    if ($user->isSuperAdmin()) {        return true;    }});
登录后复制
登录后复制

如果 before回调返回一个非空结果,那么该结果则会被当做检查的结果。

检查策略

策略类方法的调用方式和基于授权回调的闭包一样,你可以使用 Gate门面, User模型, @can指令或者辅助函数 policy。

通过 Gate 门面

Gate将会自动通过检测传递过来的类参数来判断使用哪一个策略类,因此,如果传递一个 Post实例给 denies方法,相应的, Gate会使用 PostPolicy来进行动作授权:

<?phpnamespace App\Http\Controllers;use Gate;use App\User;use App\Post;use App\Http\Controllers\Controller;class PostController extends Controller{    /**     * 更新给定文章     *     * @param  int  $id     * @return Response     */    public function update($id)    {        $post = Post::findOrFail($id);        if (Gate::denies('update', $post)) {            abort(403);        }        // 更新文章...    }}
登录后复制

通过 User 模型

User模型的 cancannot 方法将会自动使用给定参数中有效的策略类。这些方法提供了便利的方式来为应用接收到的任意 User 实例进行授权:

if ($user->can('update', $post)) {    //}if ($user->cannot('update', $post)) {    //}
登录后复制

在 Blade 模板中使用

类似的,Blade 指令 @can将会使用参数中有效的策略类:

@can('update', $post)    <!-- The Current User Can Update The Post -->@endcan
登录后复制

通过辅助函数 policy

全局的辅助函数 policy用于为给定类实例接收策略类。例如,我们可以传递一个 Post实例给帮助函数 policy来获取相应的 PostPolicy类的实例:

if (policy($post)->update($user, $post)) {    //}
登录后复制

5、 控制器授权

默认情况下,Laravel 自带的控制器基类 App\Http\Controllers\Controller使用了 AuthorizesRequeststrait,该 trait 提供了可用于快速授权给定动作的 authorize方法,如果授权不通过,则抛出 HttpException异常。

该 authorize方法和其他多种授权方法使用方法一致,例如 Gate::allows和 $user->can()。因此,我们可以这样使用 authorize方法快速授权更新 Post的请求:

<?phpnamespace App\Http\Controllers;use App\Post;use App\Http\Controllers\Controller;class PostController extends Controller{    /**     * 更新给定文章     *     * @param  int  $id     * @return Response     */    public function update($id)    {        $post = Post::findOrFail($id);        $this->authorize('update', $post);        // 更新文章...    }}
登录后复制

如果授权成功,控制器继续正常执行;然而,如果 authorize方法判断该动作授权失败,将会抛出 HttpException异常并生成带 403 Not Authorized状态码的HTTP响应。正如你所看到的, authorize方法是一个授权动作、抛出异常的便捷方法。

AuthorizesRequeststrait还提供了 authorizeForUser方法用于授权非当前用户:

$this->authorizeForUser($user, 'update', $post);
登录后复制

自动判断策略类方法

通常,一个策略类方法对应一个控制器上的方法,例如,在上面的 update方法中,控制器方法和策略类方法共享同一个方法名: update。

正是因为这个原因,Laravel 允许你简单传递实例参数到 authorize方法,被授权的权限将会自动基于调用的方法名进行判断。在本例中,由于 authorize在控制器的 update方法中被调用,那么对应的, PostPolicy上 update方法将会被调用:

/** * 更新给定文章 * * @param  int  $id * @return Response */public function update($id){    $post = Post::findOrFail($id);    $this->authorize($post);    // 更新文章...}
登录后复制
本站声明
本文内容由网友自发贡献,版权归原作者所有,本站不承担相应法律责任。如您发现有涉嫌抄袭侵权的内容,请联系admin@php.cn

热AI工具

Undresser.AI Undress

Undresser.AI Undress

人工智能驱动的应用程序,用于创建逼真的裸体照片

AI Clothes Remover

AI Clothes Remover

用于从照片中去除衣服的在线人工智能工具。

Undress AI Tool

Undress AI Tool

免费脱衣服图片

Clothoff.io

Clothoff.io

AI脱衣机

Video Face Swap

Video Face Swap

使用我们完全免费的人工智能换脸工具轻松在任何视频中换脸!

热门文章

热工具

记事本++7.3.1

记事本++7.3.1

好用且免费的代码编辑器

SublimeText3汉化版

SublimeText3汉化版

中文版,非常好用

禅工作室 13.0.1

禅工作室 13.0.1

功能强大的PHP集成开发环境

Dreamweaver CS6

Dreamweaver CS6

视觉化网页开发工具

SublimeText3 Mac版

SublimeText3 Mac版

神级代码编辑软件(SublimeText3)

热门话题

Java教程
1677
14
CakePHP 教程
1431
52
Laravel 教程
1334
25
PHP教程
1280
29
C# 教程
1257
24
说明PHP中的安全密码散列(例如,password_hash,password_verify)。为什么不使用MD5或SHA1? 说明PHP中的安全密码散列(例如,password_hash,password_verify)。为什么不使用MD5或SHA1? Apr 17, 2025 am 12:06 AM

在PHP中,应使用password_hash和password_verify函数实现安全的密码哈希处理,不应使用MD5或SHA1。1)password_hash生成包含盐值的哈希,增强安全性。2)password_verify验证密码,通过比较哈希值确保安全。3)MD5和SHA1易受攻击且缺乏盐值,不适合现代密码安全。

PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型? PHP类型提示如何起作用,包括标量类型,返回类型,联合类型和无效类型? Apr 17, 2025 am 12:25 AM

PHP类型提示提升代码质量和可读性。1)标量类型提示:自PHP7.0起,允许在函数参数中指定基本数据类型,如int、float等。2)返回类型提示:确保函数返回值类型的一致性。3)联合类型提示:自PHP8.0起,允许在函数参数或返回值中指定多个类型。4)可空类型提示:允许包含null值,处理可能返回空值的函数。

PHP和Python:解释了不同的范例 PHP和Python:解释了不同的范例 Apr 18, 2025 am 12:26 AM

PHP主要是过程式编程,但也支持面向对象编程(OOP);Python支持多种范式,包括OOP、函数式和过程式编程。PHP适合web开发,Python适用于多种应用,如数据分析和机器学习。

在PHP和Python之间进行选择:指南 在PHP和Python之间进行选择:指南 Apr 18, 2025 am 12:24 AM

PHP适合网页开发和快速原型开发,Python适用于数据科学和机器学习。1.PHP用于动态网页开发,语法简单,适合快速开发。2.Python语法简洁,适用于多领域,库生态系统强大。

PHP和Python:深入了解他们的历史 PHP和Python:深入了解他们的历史 Apr 18, 2025 am 12:25 AM

PHP起源于1994年,由RasmusLerdorf开发,最初用于跟踪网站访问者,逐渐演变为服务器端脚本语言,广泛应用于网页开发。Python由GuidovanRossum于1980年代末开发,1991年首次发布,强调代码可读性和简洁性,适用于科学计算、数据分析等领域。

PHP和框架:现代化语言 PHP和框架:现代化语言 Apr 18, 2025 am 12:14 AM

PHP在现代化进程中仍然重要,因为它支持大量网站和应用,并通过框架适应开发需求。1.PHP7提升了性能并引入了新功能。2.现代框架如Laravel、Symfony和CodeIgniter简化开发,提高代码质量。3.性能优化和最佳实践进一步提升应用效率。

为什么要使用PHP?解释的优点和好处 为什么要使用PHP?解释的优点和好处 Apr 16, 2025 am 12:16 AM

PHP的核心优势包括易于学习、强大的web开发支持、丰富的库和框架、高性能和可扩展性、跨平台兼容性以及成本效益高。1)易于学习和使用,适合初学者;2)与web服务器集成好,支持多种数据库;3)拥有如Laravel等强大框架;4)通过优化可实现高性能;5)支持多种操作系统;6)开源,降低开发成本。

PHP的影响:网络开发及以后 PHP的影响:网络开发及以后 Apr 18, 2025 am 12:10 AM

PHPhassignificantlyimpactedwebdevelopmentandextendsbeyondit.1)ItpowersmajorplatformslikeWordPressandexcelsindatabaseinteractions.2)PHP'sadaptabilityallowsittoscaleforlargeapplicationsusingframeworkslikeLaravel.3)Beyondweb,PHPisusedincommand-linescrip

See all articles