目录
授权
简介
定义能力
检查能力
通过 Gate 假面
通过用户模型检查能力
在 Blade 模板中检查能力
在表单请求中检查能力
策略(Policies)
创建策略
编写策略
检查策略
控制器授权
首页 后端开发 php教程 laravel 基础教程 -- 授权

laravel 基础教程 -- 授权

Jun 20, 2016 pm 12:27 PM

授权

简介

laravel 除了提供开箱即用的授权服务,还提供了许多简单的方式来管理授权逻辑和资源的访问控制。这些各式的方法和帮助函数便于你管理你的授权逻辑。我们将在本章中对其进行一一的解读。

定义能力

判断一个用户是否具有执行给定动作的能力的最简单的方式就是使用 Illuminate\Auth\Access\Gate 类去定义相应的能力。laravel 所提供的 AuthServiceProvider 类是定义这些能力的推荐位置。让我们来看个示例,我们定义一个 update-post 的能力,这个能力接收一个当前 User 和一个 Post 模型。在这个能力中,我们需要判断用户的 id 与 post 的 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{  /**   * Register any application authentication / authorization services.   *   * @param \Illuminate\Contracts\Auth\Access\Gate $gate   * @return void   */   public function boot(GateContract $gate)   {     $this->registerPolicies($gate);     $gate->define('update-post', function ($user, $post) {       return $user->id === $post->user_id;     });   }}
登录后复制

注意上面的示例中我们并没有检查所给定的 $user 是否为 NULL。这是因为当给定的用户没有经过认证或者用户没有经过 forUser 方法指定,Gate 类会自动的为所有的能力返回 false。

基于类的能力

除了使用 Closures 的方式作为授权检查的回调来注册能力,你还可以通过传递类中的方法来进行能力的注册,当需要的时候,类会通过服务容器来解析:

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

授权检查拦截器

有时候,你可能需要向某些特殊用户发放所有能力的通行证,这个时候,你可以使用 before 方法来定义一个回调,它会在所有的授权检查之前运行:

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

如果 before 的回调函数返回一个非空的结果,那么该结果将作为检查的结果。

你也可以使用 after 方法来定义一个在每个能力授权检查之后执行的回调函数,但是,你不能在这个回调函数内修改检查的结果:

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

检查能力

通过 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{  /**   * Update the given post.   *   * @param int $id   * @return Response   */   public function update($id)   {     $post = Post::findOrFail($id);     if (Gate::denies('update-post', $post)) {        abort(403);     }     // Update Post ...   }}
登录后复制

当然,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 模型的实例来检查用户的能力。默认的 laravel 的 App\User 模型使用了 Authorizable trait,这个性状包含两个方法: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{  /**   * Update the given post.   *   * @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);     }     // Update Post...   }}
登录后复制

当然,can 方法与 cannot 的相反:

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

在 Blade 模板中检查能力

为了方便,laravel 提供了 @can Blade 指令来快速的检查当前授权的用户是否具有指定的能力。比如:

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

你也可以通过 @else 指令来配合 @can 指令:

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

在表单请求中检查能力

你也可以通过使用表单请求(继承自 Request,用于表单验证的请求类)中自定义的 authoriza 方法来验证 Gate 假面中定义的能力:

/** * Determine if the user is authorized to make this request. * * @return bool */ public function authorize() {   $postId = $this->route('post');   return Cate::allows('update', Post::findOrFail($postId)); }
登录后复制

策略(Policies)

创建策略

为了不让你把所有的授权逻辑全部放进 AuthServiceProvider 从而使应用增长为一个庞大而笨重的应用。 laravel 允许你通过 Policy 类来分离你的授权逻辑。策略类其实就是一个包含授权逻辑组的原生 PHP 类。

首先,让我们来生成一个策略来管理我们的 Post 的授权。你可以通过 make:policy 命令来生成一个策略。所生成的策略会存放在 app/Policies 目录:

php artisan make:policy PostPolicy
登录后复制

注册策略

一旦策略存在,我们还需要在 Gate 类中进行注册。在 AuthServiceProvider 中包含了一个 policies 属性,该属性存放所有实体与策略间的映射。所以,我们需要将 Post 模型的策略指定到 PostPolice 类:

<?phpnamespace App\Providers;use App\Post;use App\Policies\PostPolicy;use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;class AuthServiceProvider extends ServiceProvider{  /**   * The policy mappings for the application.   *   * @var array   */   protected $policies = [     Post::class => PostPolicy::class,   ];   /**    * Register any application authentication / authorization services.    *     * @param \Illuminate\Contracts\Auth\Access\Gate $gate    * @return void    */    public function boot(GateContract $gate)    {      $this->registerPolicies($gate);     }}
登录后复制

编写策略

一旦策略被生成和注册后,我们就可以为所有能力的授权添加验证方法。例如,让我们在 PostPolicy 类中定义一个 update 方法,用来验证所给定的用户是否具有 update Post 的能力:

<?phpnamespace App\Policies;use App\Uesr;use App\Post;class PostPolicy{  /**   * Determine if the given post can be updated by the user.   *   * @param \App\User $user   * @param \App\Post $post   * @return bool   */   public function update(User $user, Post $post)   {     return $user->id === $post->user_id;   }}
登录后复制

你可以继续在策略中添加其他所需进行授权验证的方法。比如,你可以继续为验证 Post 的各种动作而定义 show,destroy,或者 addComment 方法。

注意:所有的策略类都是通过服务容器解析而来。这意味着你可以使用类型提示来在策略类的构造函数中进行依赖注入所需要的依赖。

拦截所有检查

有时候,你可能需要发放给指定用户具有所有能力的通行证,这时候,你可以在策略类中定义 before 方法。该方法会在策略中其他所有方法被执行前运行:

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

如果 before 方法返回一个非空值,那么其结果将会用来作为授权验证的结果的判断依据。

检查策略

策略类的方法和基于授权回调的方法一样通过相同的方式作为 Closure 被调用。你可以使用 Gate 假面,User 模型,@can Blade 指令或者 policy helper 来进行授权的检查。

通过 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{  /**   * Update the given post.   *    * @param int $id   * @return Response   */   public function update($id)   {     $post = Post::findOrFail($id);     if (Gate::denies('update', $post)) {       abort(403);     }     // Update Post...   }}
登录后复制

通过用户的模型

User 模型中的 can 和 cannot 方法也会在所给定参数可用时自动匹配相应的策略。这些方法提供了一种便利的方式去验证任意用户实例是否具有所给定的能力:

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

通过 Blade 模板

就像我们所期望的,@can Blade 指令会在所给定参数可用时自动匹配相应的策略:

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

通过策略 Helper

全局帮助方法 policy 可以通过所给定的类解析相应的 Policy 类。例如,我们可以传递一个 Post 实例到 policy 帮助方法,该方法会返回相应的 PostPolicy 类:

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

控制器授权

默认的,在 laravel 中基于 Ap\Http\Controllers\Controller 的类都引入了 AuthorizesRequests 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{  /**   * Update the given post.   *   * @param int $id   * @return Response   */   public function update($id)   {     $post = Post::findOrFail($id);     $this->authorize('update', $post);     // Update Post...   }}
登录后复制

如果这个动作通过了授权,控制器将继续执行下面的逻辑。否则会自动的抛出一个 HttpException 错误,这个错误会生成一个 403 Not Authorized 的 Http 响应。就如你所看到的, authorize 方法是一个非常方便的方法,它的方便之处就在于只使用一条语句执行了授权的验证或抛出异常。

AuthorizeRequests trait 也提供了 authorizeForUser 方法来进行非当前用户的用户与给定能力的鉴权:

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

自动的确定策略方法

通常的,策略类中的方法是与控制器中的方法相对应的。比如在上面的 update 方法中,控制器的方法和策略的方法使用了相同的命名: update。

由于这个原因,laravel 允许你通过简单的传递一个实例参数到 authorize 方法,在能力的鉴定中,laravel 会根据当前方法的命名自动的确定策略方法的调用。在上面的例子中,由于 authorize 方法是在控制器中的 update 方法中调用的,所以 PostPolicy 中的 update 将会被调用:

/** * Update the given post. *  * @param int $id * @return Response */ public function update($id) {   $post = Post::findOrFail($id);   $this->authorize($post);   // Update 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

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

热门文章

<🎜>:泡泡胶模拟器无穷大 - 如何获取和使用皇家钥匙
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
北端:融合系统,解释
3 周前 By 尊渡假赌尊渡假赌尊渡假赌
Mandragora:巫婆树的耳语 - 如何解锁抓钩
3 周前 By 尊渡假赌尊渡假赌尊渡假赌

热工具

记事本++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教程
1665
14
CakePHP 教程
1424
52
Laravel 教程
1322
25
PHP教程
1270
29
C# 教程
1250
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和Python:比较两种流行的编程语言 PHP和Python:比较两种流行的编程语言 Apr 14, 2025 am 12:13 AM

PHP和Python各有优势,选择依据项目需求。1.PHP适合web开发,尤其快速开发和维护网站。2.Python适用于数据科学、机器学习和人工智能,语法简洁,适合初学者。

PHP行动:现实世界中的示例和应用程序 PHP行动:现实世界中的示例和应用程序 Apr 14, 2025 am 12:19 AM

PHP在电子商务、内容管理系统和API开发中广泛应用。1)电子商务:用于购物车功能和支付处理。2)内容管理系统:用于动态内容生成和用户管理。3)API开发:用于RESTfulAPI开发和API安全性。通过性能优化和最佳实践,PHP应用的效率和可维护性得以提升。

PHP:网络开发的关键语言 PHP:网络开发的关键语言 Apr 13, 2025 am 12:08 AM

PHP是一种广泛应用于服务器端的脚本语言,特别适合web开发。1.PHP可以嵌入HTML,处理HTTP请求和响应,支持多种数据库。2.PHP用于生成动态网页内容,处理表单数据,访问数据库等,具有强大的社区支持和开源资源。3.PHP是解释型语言,执行过程包括词法分析、语法分析、编译和执行。4.PHP可以与MySQL结合用于用户注册系统等高级应用。5.调试PHP时,可使用error_reporting()和var_dump()等函数。6.优化PHP代码可通过缓存机制、优化数据库查询和使用内置函数。7

PHP的持久相关性:它还活着吗? PHP的持久相关性:它还活着吗? Apr 14, 2025 am 12:12 AM

PHP仍然具有活力,其在现代编程领域中依然占据重要地位。1)PHP的简单易学和强大社区支持使其在Web开发中广泛应用;2)其灵活性和稳定性使其在处理Web表单、数据库操作和文件处理等方面表现出色;3)PHP不断进化和优化,适用于初学者和经验丰富的开发者。

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 15, 2025 am 12:07 AM

PHP和Python各有优劣,选择取决于项目需求和个人偏好。1.PHP适合快速开发和维护大型Web应用。2.Python在数据科学和机器学习领域占据主导地位。

PHP与其他语言:比较 PHP与其他语言:比较 Apr 13, 2025 am 12:19 AM

PHP适合web开发,特别是在快速开发和处理动态内容方面表现出色,但不擅长数据科学和企业级应用。与Python相比,PHP在web开发中更具优势,但在数据科学领域不如Python;与Java相比,PHP在企业级应用中表现较差,但在web开发中更灵活;与JavaScript相比,PHP在后端开发中更简洁,但在前端开发中不如JavaScript。

See all articles