授權
簡介
除了提供內建的身份驗證服務之外,Laravel 還提供了一種簡單的方式來授權使用者對給定資源的行為。例如,即使使用者已通過身份驗證,他們也可能未被授權更新或刪除應用程式管理的某些 Eloquent 模型或資料庫記錄。Laravel 的授權功能提供了一種簡單、有組織的方式來管理這些類型的授權檢查。
Laravel 提供了兩種主要的授權行為方式:閘道和策略。將閘道和策略視為路由和控制器。閘道提供了一種簡單、基於閉包的授權方法,而策略(如控制器)則圍繞特定模型或資源對邏輯進行分組。在本文件中,我們將首先探討閘道,然後檢視策略。
在建構應用程式時,您不需要選擇專門使用閘道或專門使用策略。大多數應用程式很可能包含閘道和策略的混合,這完全沒有問題!閘道最適用於與任何模型或資源無關的行為,例如檢視管理員儀表板。相反,當您希望授權特定模型或資源的行為時,應使用策略。
閘道
撰寫閘道
閘道是學習 Laravel 授權功能基礎知識的好方法;但是,在建構穩健的 Laravel 應用程式時,您應考慮使用策略來組織您的授權規則。
閘道只是閉包,用於確定使用者是否有權執行給定的行為。通常,閘道是使用 Gate
facade 在 App\Providers\AppServiceProvider
類別的 boot
方法中定義的。閘道始終接收使用者實例作為其第一個參數,並且可以選擇性地接收其他參數,例如相關的 Eloquent 模型。
在本範例中,我們將定義一個閘道,以確定使用者是否可以更新給定的 App\Models\Post
模型。閘道將透過比較使用者的 id
與建立文章的使用者的 user_id
來完成此操作
1use App\Models\Post; 2use App\Models\User; 3use Illuminate\Support\Facades\Gate; 4 5/** 6 * Bootstrap any application services. 7 */ 8public function boot(): void 9{10 Gate::define('update-post', function (User $user, Post $post) {11 return $user->id === $post->user_id;12 });13}
與控制器類似,閘道也可以使用類別回呼陣列來定義
1use App\Policies\PostPolicy; 2use Illuminate\Support\Facades\Gate; 3 4/** 5 * Bootstrap any application services. 6 */ 7public function boot(): void 8{ 9 Gate::define('update-post', [PostPolicy::class, 'update']);10}
授權行為
若要使用閘道授權行為,您應使用 Gate
facade 提供的 allows
或 denies
方法。請注意,您不需要將目前已驗證的使用者傳遞給這些方法。Laravel 將自動處理將使用者傳遞到閘道閉包中。通常在應用程式的控制器中呼叫閘道授權方法,然後再執行需要授權的行為
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Models\Post; 7use Illuminate\Http\RedirectResponse; 8use Illuminate\Http\Request; 9use Illuminate\Support\Facades\Gate;10 11class PostController extends Controller12{13 /**14 * Update the given post.15 */16 public function update(Request $request, Post $post): RedirectResponse17 {18 if (! Gate::allows('update-post', $post)) {19 abort(403);20 }21 22 // Update the post...23 24 return redirect('/posts');25 }26}
如果您想確定是否授權目前已驗證使用者以外的使用者執行行為,可以使用 Gate
facade 上的 forUser
方法
1if (Gate::forUser($user)->allows('update-post', $post)) {2 // The user can update the post...3}4 5if (Gate::forUser($user)->denies('update-post', $post)) {6 // The user can't update the post...7}
您可以使用 any
或 none
方法一次授權多個行為
1if (Gate::any(['update-post', 'delete-post'], $post)) {2 // The user can update or delete the post...3}4 5if (Gate::none(['update-post', 'delete-post'], $post)) {6 // The user can't update or delete the post...7}
授權或拋出例外
如果您想嘗試授權行為,並且在不允許使用者執行給定行為時自動拋出 Illuminate\Auth\Access\AuthorizationException
,您可以使用 Gate
facade 的 authorize
方法。AuthorizationException
的實例會自動由 Laravel 轉換為 403 HTTP 回應
1Gate::authorize('update-post', $post);2 3// The action is authorized...
提供額外上下文
用於授權能力的閘道方法(allows
、denies
、check
、any
、none
、authorize
、can
、cannot
)和授權Blade 指令(@can
、@cannot
、@canany
)可以接收陣列作為其第二個參數。這些陣列元素作為參數傳遞給閘道閉包,並且可以在制定授權決策時用於額外上下文
1use App\Models\Category; 2use App\Models\User; 3use Illuminate\Support\Facades\Gate; 4 5Gate::define('create-post', function (User $user, Category $category, bool $pinned) { 6 if (! $user->canPublishToGroup($category->group)) { 7 return false; 8 } elseif ($pinned && ! $user->canPinPosts()) { 9 return false;10 }11 12 return true;13});14 15if (Gate::check('create-post', [$category, $pinned])) {16 // The user can create the post...17}
閘道回應
到目前為止,我們僅檢視了傳回簡單布林值的閘道。但是,有時您可能希望傳回更詳細的回應,包括錯誤訊息。為此,您可以從閘道傳回 Illuminate\Auth\Access\Response
1use App\Models\User;2use Illuminate\Auth\Access\Response;3use Illuminate\Support\Facades\Gate;4 5Gate::define('edit-settings', function (User $user) {6 return $user->isAdmin7 ? Response::allow()8 : Response::deny('You must be an administrator.');9});
即使您從閘道傳回授權回應,Gate::allows
方法仍然會傳回簡單的布林值;但是,您可以使用 Gate::inspect
方法來取得閘道傳回的完整授權回應
1$response = Gate::inspect('edit-settings');2 3if ($response->allowed()) {4 // The action is authorized...5} else {6 echo $response->message();7}
當使用 Gate::authorize
方法時,如果行為未經授權,該方法會拋出 AuthorizationException
,則授權回應提供的錯誤訊息將傳播到 HTTP 回應
1Gate::authorize('edit-settings');2 3// The action is authorized...
自訂 HTTP 回應狀態
當透過閘道拒絕行為時,會傳回 403
HTTP 回應;但是,有時傳回替代的 HTTP 狀態碼可能很有用。您可以使用 Illuminate\Auth\Access\Response
類別上的 denyWithStatus
靜態建構子,自訂授權檢查失敗時傳回的 HTTP 狀態碼
1use App\Models\User;2use Illuminate\Auth\Access\Response;3use Illuminate\Support\Facades\Gate;4 5Gate::define('edit-settings', function (User $user) {6 return $user->isAdmin7 ? Response::allow()8 : Response::denyWithStatus(404);9});
由於透過 404
回應隱藏資源是 Web 應用程式的常見模式,因此為了方便起見,提供了 denyAsNotFound
方法
1use App\Models\User;2use Illuminate\Auth\Access\Response;3use Illuminate\Support\Facades\Gate;4 5Gate::define('edit-settings', function (User $user) {6 return $user->isAdmin7 ? Response::allow()8 : Response::denyAsNotFound();9});
攔截閘道檢查
有時,您可能希望將所有能力授予特定使用者。您可以使用 before
方法來定義在所有其他授權檢查之前執行的閉包
1use App\Models\User;2use Illuminate\Support\Facades\Gate;3 4Gate::before(function (User $user, string $ability) {5 if ($user->isAdministrator()) {6 return true;7 }8});
如果 before
閉包傳回非 null 結果,則該結果將被視為授權檢查的結果。
您可以使用 after
方法來定義在所有其他授權檢查之後執行的閉包
1use App\Models\User;2 3Gate::after(function (User $user, string $ability, bool|null $result, mixed $arguments) {4 if ($user->isAdministrator()) {5 return true;6 }7});
除非閘道或策略傳回 null
,否則 after
閉包傳回的值不會覆寫授權檢查的結果。
內聯授權
有時,您可能希望確定目前已驗證的使用者是否有權執行給定的行為,而無需撰寫與該行為對應的專用閘道。Laravel 允許您透過 Gate::allowIf
和 Gate::denyIf
方法執行這些類型的「內聯」授權檢查。內聯授權不會執行任何已定義的「之前」或「之後」授權掛鉤
1use App\Models\User;2use Illuminate\Support\Facades\Gate;3 4Gate::allowIf(fn (User $user) => $user->isAdministrator());5 6Gate::denyIf(fn (User $user) => $user->banned());
如果行為未經授權,或者目前未驗證任何使用者,Laravel 將自動拋出 Illuminate\Auth\Access\AuthorizationException
例外。AuthorizationException
的實例會自動由 Laravel 的例外處理常式轉換為 403 HTTP 回應。
建立策略
產生策略
策略是圍繞特定模型或資源組織授權邏輯的類別。例如,如果您的應用程式是部落格,您可能有一個 App\Models\Post
模型和一個對應的 App\Policies\PostPolicy
,用於授權使用者行為,例如建立或更新文章。
您可以使用 make:policy
Artisan 命令產生策略。產生的策略將放置在 app/Policies
目錄中。如果此目錄在您的應用程式中不存在,Laravel 將為您建立它
1php artisan make:policy PostPolicy
make:policy
命令將產生一個空策略類別。如果您想產生一個具有與檢視、建立、更新和刪除資源相關的範例策略方法的類別,您可以在執行命令時提供 --model
選項
1php artisan make:policy PostPolicy --model=Post
註冊策略
策略探索
預設情況下,只要模型和策略遵循標準 Laravel 命名慣例,Laravel 就會自動探索策略。具體來說,策略必須位於包含模型的目錄或其上方的 Policies
目錄中。因此,例如,模型可以放置在 app/Models
目錄中,而策略可以放置在 app/Policies
目錄中。在這種情況下,Laravel 將在 app/Models/Policies
然後是 app/Policies
中檢查策略。此外,策略名稱必須與模型名稱匹配,並且具有 Policy
後綴。因此,User
模型將對應於 UserPolicy
策略類別。
如果您想定義自己的策略探索邏輯,您可以使用 Gate::guessPolicyNamesUsing
方法註冊自訂策略探索回呼。通常,此方法應從應用程式 AppServiceProvider
的 boot
方法中呼叫
1use Illuminate\Support\Facades\Gate;2 3Gate::guessPolicyNamesUsing(function (string $modelClass) {4 // Return the name of the policy class for the given model...5});
手動註冊策略
使用 Gate
facade,您可以在應用程式 AppServiceProvider
的 boot
方法中手動註冊策略及其對應的模型
1use App\Models\Order; 2use App\Policies\OrderPolicy; 3use Illuminate\Support\Facades\Gate; 4 5/** 6 * Bootstrap any application services. 7 */ 8public function boot(): void 9{10 Gate::policy(Order::class, OrderPolicy::class);11}
撰寫策略
策略方法
註冊策略類別後,您可以為其授權的每個行為新增方法。例如,讓我們在 PostPolicy
上定義一個 update
方法,該方法確定給定的 App\Models\User
是否可以更新給定的 App\Models\Post
實例。
update
方法將接收 User
和 Post
實例作為其參數,並且應傳回 true
或 false
,指示是否授權使用者更新給定的 Post
。因此,在本範例中,我們將驗證使用者的 id
是否與文章上的 user_id
相符
1<?php 2 3namespace App\Policies; 4 5use App\Models\Post; 6use App\Models\User; 7 8class PostPolicy 9{10 /**11 * Determine if the given post can be updated by the user.12 */13 public function update(User $user, Post $post): bool14 {15 return $user->id === $post->user_id;16 }17}
您可以繼續在策略上定義其他方法,以滿足其授權的各種行為的需求。例如,您可能會定義 view
或 delete
方法來授權各種與 Post
相關的行為,但請記住,您可以隨意為策略方法命名。
如果您在使用 Artisan 控制台產生策略時使用了 --model
選項,它將已包含用於 viewAny
、view
、create
、update
、delete
、restore
和 forceDelete
行為的方法。
所有策略都透過 Laravel 服務容器解析,允許您在策略的建構子中輸入任何需要的依賴項,以便自動注入它們。
策略回應
到目前為止,我們僅檢視了傳回簡單布林值的策略方法。但是,有時您可能希望傳回更詳細的回應,包括錯誤訊息。為此,您可以從策略方法傳回 Illuminate\Auth\Access\Response
實例
1use App\Models\Post; 2use App\Models\User; 3use Illuminate\Auth\Access\Response; 4 5/** 6 * Determine if the given post can be updated by the user. 7 */ 8public function update(User $user, Post $post): Response 9{10 return $user->id === $post->user_id11 ? Response::allow()12 : Response::deny('You do not own this post.');13}
從策略傳回授權回應時,Gate::allows
方法仍然會傳回簡單的布林值;但是,您可以使用 Gate::inspect
方法來取得閘道傳回的完整授權回應
1use Illuminate\Support\Facades\Gate;2 3$response = Gate::inspect('update', $post);4 5if ($response->allowed()) {6 // The action is authorized...7} else {8 echo $response->message();9}
當使用 Gate::authorize
方法時,如果行為未經授權,該方法會拋出 AuthorizationException
,則授權回應提供的錯誤訊息將傳播到 HTTP 回應
1Gate::authorize('update', $post);2 3// The action is authorized...
自訂 HTTP 回應狀態
當透過策略方法拒絕行為時,會傳回 403
HTTP 回應;但是,有時傳回替代的 HTTP 狀態碼可能很有用。您可以使用 Illuminate\Auth\Access\Response
類別上的 denyWithStatus
靜態建構子,自訂授權檢查失敗時傳回的 HTTP 狀態碼
1use App\Models\Post; 2use App\Models\User; 3use Illuminate\Auth\Access\Response; 4 5/** 6 * Determine if the given post can be updated by the user. 7 */ 8public function update(User $user, Post $post): Response 9{10 return $user->id === $post->user_id11 ? Response::allow()12 : Response::denyWithStatus(404);13}
由於透過 404
回應隱藏資源是 Web 應用程式的常見模式,因此為了方便起見,提供了 denyAsNotFound
方法
1use App\Models\Post; 2use App\Models\User; 3use Illuminate\Auth\Access\Response; 4 5/** 6 * Determine if the given post can be updated by the user. 7 */ 8public function update(User $user, Post $post): Response 9{10 return $user->id === $post->user_id11 ? Response::allow()12 : Response::denyAsNotFound();13}
不帶模型的方法
某些策略方法僅接收目前已驗證使用者的實例。這種情況在授權 create
行為時最常見。例如,如果您要建立部落格,您可能希望確定使用者是否有權建立任何文章。在這些情況下,您的策略方法應僅預期接收使用者實例
1/**2 * Determine if the given user can create posts.3 */4public function create(User $user): bool5{6 return $user->role == 'writer';7}
訪客使用者
預設情況下,如果傳入的 HTTP 請求不是由已驗證的使用者發起的,則所有閘道和策略都會自動傳回 false
。但是,您可以透過宣告「可選」類型提示或為使用者引數定義提供 null
預設值,來允許這些授權檢查傳遞到您的閘道和策略。
1<?php 2 3namespace App\Policies; 4 5use App\Models\Post; 6use App\Models\User; 7 8class PostPolicy 9{10 /**11 * Determine if the given post can be updated by the user.12 */13 public function update(?User $user, Post $post): bool14 {15 return $user?->id === $post->user_id;16 }17}
策略篩選器
對於某些使用者,您可能希望授權給定策略中的所有行為。為了實現此目的,請在策略上定義 before
方法。before
方法將在策略上的任何其他方法之前執行,讓您有機會在實際呼叫預期的策略方法之前授權行為。此功能最常用於授權應用程式管理員執行任何行為
1use App\Models\User; 2 3/** 4 * Perform pre-authorization checks. 5 */ 6public function before(User $user, string $ability): bool|null 7{ 8 if ($user->isAdministrator()) { 9 return true;10 }11 12 return null;13}
如果您想拒絕特定類型使用者的所有授權檢查,則可以從 before
方法傳回 false
。如果傳回 null
,則授權檢查將退回到策略方法。
如果策略類別不包含與要檢查的能力名稱匹配的方法名稱,則不會呼叫策略類別的 before
方法。
使用策略授權行為
透過使用者模型
Laravel 應用程式隨附的 App\Models\User
模型包含兩個有助於授權行為的方法:can
和 cannot
。can
和 cannot
方法接收您要授權的行為名稱和相關模型。例如,讓我們確定是否授權使用者更新給定的 App\Models\Post
模型。通常,這將在控制器方法中完成
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Models\Post; 7use Illuminate\Http\RedirectResponse; 8use Illuminate\Http\Request; 9 10class PostController extends Controller11{12 /**13 * Update the given post.14 */15 public function update(Request $request, Post $post): RedirectResponse16 {17 if ($request->user()->cannot('update', $post)) {18 abort(403);19 }20 21 // Update the post...22 23 return redirect('/posts');24 }25}
如果為給定模型註冊了策略,則 can
方法將自動呼叫適當的策略並傳回布林值結果。如果未為模型註冊策略,則 can
方法將嘗試呼叫與給定行為名稱匹配的基於閉包的閘道。
不需要模型的行為
請記住,某些行為可能對應於策略方法,例如 create
,這些方法不需要模型實例。在這些情況下,您可以將類別名稱傳遞給 can
方法。類別名稱將用於確定在授權行為時要使用的策略
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Models\Post; 7use Illuminate\Http\RedirectResponse; 8use Illuminate\Http\Request; 9 10class PostController extends Controller11{12 /**13 * Create a post.14 */15 public function store(Request $request): RedirectResponse16 {17 if ($request->user()->cannot('create', Post::class)) {18 abort(403);19 }20 21 // Create the post...22 23 return redirect('/posts');24 }25}
透過 Gate
Facade
除了 App\Models\User
模型提供有用的方法之外,您始終可以透過 Gate
facade 的 authorize
方法授權行為。
與 can
方法類似,此方法接受您要授權的行為名稱和相關模型。如果行為未經授權,則 authorize
方法將拋出 Illuminate\Auth\Access\AuthorizationException
例外,Laravel 例外處理常式會自動將其轉換為狀態碼為 403 的 HTTP 回應
1<?php 2 3namespace App\Http\Controllers; 4 5use App\Http\Controllers\Controller; 6use App\Models\Post; 7use Illuminate\Http\RedirectResponse; 8use Illuminate\Http\Request; 9use Illuminate\Support\Facades\Gate;10 11class PostController extends Controller12{13 /**14 * Update the given blog post.15 *16 * @throws \Illuminate\Auth\Access\AuthorizationException17 */18 public function update(Request $request, Post $post): RedirectResponse19 {20 Gate::authorize('update', $post);21 22 // The current user can update the blog post...23 24 return redirect('/posts');25 }26}
不需要模型的行為
如前所述,某些策略方法(如 create
)不需要模型實例。在這些情況下,您應將類別名稱傳遞給 authorize
方法。類別名稱將用於確定在授權行為時要使用的策略
1use App\Models\Post; 2use Illuminate\Http\RedirectResponse; 3use Illuminate\Http\Request; 4use Illuminate\Support\Facades\Gate; 5 6/** 7 * Create a new blog post. 8 * 9 * @throws \Illuminate\Auth\Access\AuthorizationException10 */11public function create(Request $request): RedirectResponse12{13 Gate::authorize('create', Post::class);14 15 // The current user can create blog posts...16 17 return redirect('/posts');18}
透過中介層
Laravel 包含一個中介層,可以在傳入的請求到達您的路由或控制器之前授權行為。預設情況下,可以使用 can
中介層別名將 Illuminate\Auth\Middleware\Authorize
中介層附加到路由,Laravel 會自動註冊該別名。讓我們探討一個使用 can
中介層授權使用者可以更新文章的範例
1use App\Models\Post;2 3Route::put('/post/{post}', function (Post $post) {4 // The current user may update the post...5})->middleware('can:update,post');
在本範例中,我們將兩個引數傳遞給 can
中介層。第一個是我們希望授權的行為名稱,第二個是我們希望傳遞給策略方法的路由參數。在本例中,由於我們正在使用隱式模型綁定,因此 App\Models\Post
模型將傳遞給策略方法。如果未授權使用者執行給定的行為,中介層將傳回狀態碼為 403 的 HTTP 回應。
為了方便起見,您也可以使用 can
方法將 can
中介層附加到您的路由
1use App\Models\Post;2 3Route::put('/post/{post}', function (Post $post) {4 // The current user may update the post...5})->can('update', 'post');
不需要模型的行為
同樣,某些策略方法(如 create
)不需要模型實例。在這些情況下,您可以將類別名稱傳遞給中介層。類別名稱將用於確定在授權行為時要使用的策略
1Route::post('/post', function () {2 // The current user may create posts...3})->middleware('can:create,App\Models\Post');
在字串中介層定義中指定完整的類別名稱可能會變得繁瑣。因此,您可以選擇使用 can
方法將 can
中介層附加到您的路由
1use App\Models\Post;2 3Route::post('/post', function () {4 // The current user may create posts...5})->can('create', Post::class);
透過 Blade 模板
在撰寫 Blade 模板時,您可能希望僅在授權使用者執行給定行為時才顯示頁面的某一部分。例如,您可能希望僅在使用者實際上可以更新文章時才顯示部落格文章的更新表單。在這種情況下,您可以使用 @can
和 @cannot
指令
1@can('update', $post) 2 <!-- The current user can update the post... --> 3@elsecan('create', App\Models\Post::class) 4 <!-- The current user can create new posts... --> 5@else 6 <!-- ... --> 7@endcan 8 9@cannot('update', $post)10 <!-- The current user cannot update the post... -->11@elsecannot('create', App\Models\Post::class)12 <!-- The current user cannot create new posts... -->13@endcannot
這些指令是撰寫 @if
和 @unless
語句的便捷快捷方式。上面的 @can
和 @cannot
語句等效於以下語句
1@if (Auth::user()->can('update', $post))2 <!-- The current user can update the post... -->3@endif4 5@unless (Auth::user()->can('update', $post))6 <!-- The current user cannot update the post... -->7@endunless
您也可以確定是否授權使用者從給定的行為陣列中執行任何行為。為了實現此目的,請使用 @canany
指令
1@canany(['update', 'view', 'delete'], $post)2 <!-- The current user can update, view, or delete the post... -->3@elsecanany(['create'], \App\Models\Post::class)4 <!-- The current user can create a post... -->5@endcanany
不需要模型的行為
與大多數其他授權方法類似,如果行為不需要模型實例,您可以將類別名稱傳遞給 @can
和 @cannot
指令
1@can('create', App\Models\Post::class)2 <!-- The current user can create posts... -->3@endcan4 5@cannot('create', App\Models\Post::class)6 <!-- The current user can't create posts... -->7@endcannot
提供額外上下文
使用策略授權行為時,您可以將陣列作為第二個引數傳遞給各種授權函式和輔助函式。陣列中的第一個元素將用於確定應調用哪個策略,而陣列的其餘元素將作為參數傳遞給策略方法,並且可以在制定授權決策時用於額外上下文。例如,考慮以下包含額外 $category
參數的 PostPolicy
方法定義
1/**2 * Determine if the given post can be updated by the user.3 */4public function update(User $user, Post $post, int $category): bool5{6 return $user->id === $post->user_id &&7 $user->canUpdateCategory($category);8}
當嘗試確定是否授權已驗證的使用者可以更新給定的文章時,我們可以像這樣調用此策略方法
1/** 2 * Update the given blog post. 3 * 4 * @throws \Illuminate\Auth\Access\AuthorizationException 5 */ 6public function update(Request $request, Post $post): RedirectResponse 7{ 8 Gate::authorize('update', [$post, $request->category]); 9 10 // The current user can update the blog post...11 12 return redirect('/posts');13}
授權 & Inertia
雖然授權必須始終在伺服器上處理,但通常可以方便地向您的前端應用程式提供授權資料,以便正確呈現應用程式的 UI。Laravel 沒有定義用於向基於 Inertia 的前端公開授權資訊的必要慣例。
但是,如果您使用的是 Laravel 基於 Inertia 的入門套件之一,則您的應用程式已包含 HandleInertiaRequests
中介層。在此中介層的 share
方法中,您可以傳回將提供給應用程式中所有 Inertia 頁面的共享資料。此共享資料可以用作定義使用者授權資訊的便捷位置
1<?php 2 3namespace App\Http\Middleware; 4 5use App\Models\Post; 6use Illuminate\Http\Request; 7use Inertia\Middleware; 8 9class HandleInertiaRequests extends Middleware10{11 // ...12 13 /**14 * Define the props that are shared by default.15 *16 * @return array<string, mixed>17 */18 public function share(Request $request)19 {20 return [21 ...parent::share($request),22 'auth' => [23 'user' => $request->user(),24 'permissions' => [25 'post' => [26 'create' => $request->user()->can('create', Post::class),27 ],28 ],29 ],30 ];31 }32}