[ Laravel 5.2 文档 ] 服务 -- 用户授权
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模型的 can
和 cannot
方法将会自动使用给定参数中有效的策略类。这些方法提供了便利的方式来为应用接收到的任意 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); // 更新文章...}

熱AI工具

Undresser.AI Undress
人工智慧驅動的應用程序,用於創建逼真的裸體照片

AI Clothes Remover
用於從照片中去除衣服的線上人工智慧工具。

Undress AI Tool
免費脫衣圖片

Clothoff.io
AI脫衣器

Video Face Swap
使用我們完全免費的人工智慧換臉工具,輕鬆在任何影片中換臉!

熱門文章

熱工具

記事本++7.3.1
好用且免費的程式碼編輯器

SublimeText3漢化版
中文版,非常好用

禪工作室 13.0.1
強大的PHP整合開發環境

Dreamweaver CS6
視覺化網頁開發工具

SublimeText3 Mac版
神級程式碼編輯軟體(SublimeText3)

在PHP中,應使用password_hash和password_verify函數實現安全的密碼哈希處理,不應使用MD5或SHA1。1)password_hash生成包含鹽值的哈希,增強安全性。 2)password_verify驗證密碼,通過比較哈希值確保安全。 3)MD5和SHA1易受攻擊且缺乏鹽值,不適合現代密碼安全。

PHP和Python各有優勢,選擇依據項目需求。 1.PHP適合web開發,尤其快速開發和維護網站。 2.Python適用於數據科學、機器學習和人工智能,語法簡潔,適合初學者。

PHP在電子商務、內容管理系統和API開發中廣泛應用。 1)電子商務:用於購物車功能和支付處理。 2)內容管理系統:用於動態內容生成和用戶管理。 3)API開發:用於RESTfulAPI開發和API安全性。通過性能優化和最佳實踐,PHP應用的效率和可維護性得以提升。

PHP是一種廣泛應用於服務器端的腳本語言,特別適合web開發。 1.PHP可以嵌入HTML,處理HTTP請求和響應,支持多種數據庫。 2.PHP用於生成動態網頁內容,處理表單數據,訪問數據庫等,具有強大的社區支持和開源資源。 3.PHP是解釋型語言,執行過程包括詞法分析、語法分析、編譯和執行。 4.PHP可以與MySQL結合用於用戶註冊系統等高級應用。 5.調試PHP時,可使用error_reporting()和var_dump()等函數。 6.優化PHP代碼可通過緩存機制、優化數據庫查詢和使用內置函數。 7

PHP類型提示提升代碼質量和可讀性。 1)標量類型提示:自PHP7.0起,允許在函數參數中指定基本數據類型,如int、float等。 2)返回類型提示:確保函數返回值類型的一致性。 3)聯合類型提示:自PHP8.0起,允許在函數參數或返回值中指定多個類型。 4)可空類型提示:允許包含null值,處理可能返回空值的函數。

PHP仍然具有活力,其在現代編程領域中依然佔據重要地位。 1)PHP的簡單易學和強大社區支持使其在Web開發中廣泛應用;2)其靈活性和穩定性使其在處理Web表單、數據庫操作和文件處理等方面表現出色;3)PHP不斷進化和優化,適用於初學者和經驗豐富的開發者。

PHP適合web開發,特別是在快速開發和處理動態內容方面表現出色,但不擅長數據科學和企業級應用。與Python相比,PHP在web開發中更具優勢,但在數據科學領域不如Python;與Java相比,PHP在企業級應用中表現較差,但在web開發中更靈活;與JavaScript相比,PHP在後端開發中更簡潔,但在前端開發中不如JavaScript。

PHP和Python各有優劣,選擇取決於項目需求和個人偏好。 1.PHP適合快速開發和維護大型Web應用。 2.Python在數據科學和機器學習領域佔據主導地位。
