Ray Lee | 李宗叡
Learn or Die
Published in
23 min readDec 29, 2020

--

Photo by Dan Nelson on Unsplash

# 版本

Laravel 7.x

# 前言

我喜歡使用 Laravel 開發的感覺, 除了開發快速, 程式碼簡潔且優雅之外, Laravel 框架本身也是一個很好的學習參照物。 本篇主要將官方文件重點整理成 Q&A 的形式呈現, 原子化的概念, 這方式並不適用於每個人, 但若對你有幫助, 我會很開心。

# Gates

# Writing Gates

Laravel Authentication 中, 主要有哪兩種 authorization 方式?

gates and policies

以下的 Laravel example code 的意思是?

  • Example:
<?php
public function boot()
{
$this->registerPolicies();

Gate::define('edit-settings', function ($user) {
return $user->isAdmin;
});
}
  • Answer: 在 AuthServiceProvider 的 boot() 當中, 使用 Gate::define 定義一個名為 'edit-settings' 的 closure gate

以下的 Laravel example code 的意思是?

  • Example:
<?php
public function boot()
{
$this->registerPolicies();

Gate::define('update-post', 'class@method');
}
  • Answer: 在定義一個 Gate closure based rule 時, 也可以選擇由指定的 class@method 來執行驗證邏輯

# Authorizing Actions

Laravel Authentication 中, 當我使用 Gate 時, 需要帶入 current $user 嗎?

不需要

以下的 Laravel example code 的意思是?

  • Example:
<?php
if (Gate::allows('update-post', $post)) {
// The current user can update the post...
}
  • Answer: 判斷當前 authenticated user 是否被允許 update $post, 會調用該 'update-post' closure gate

以下的 Laravel example code 的意思是?

  • Example:
<?php
if (Gate::denies('update-post', $post)) {
// The current user can't update the post...
}
  • Answer: 判斷當前 authenticated user 是否不被允許 update $post, 會 closure gate update-post 的驗證邏輯

以下的 Laravel example code 的意思是?

  • Example:
<?php
if (Gate::forUser($user)->allows('update-post', $post)) {
// The user can update the post...
}
  • Answer: 判斷 $user 是否 被允許 update $post, 會執行 update-post 這個 closure gate

以下的 Laravel example code 的意思是?

  • Example:
<?php
if (Gate::any(['update-post', 'delete-post'], $post)) {
// The user can update or delete the post
}
  • Answer: 判斷當前 authenticated user 是否 被允許 update $postdelete $post, 會執行 update-post 以及 delete-post 這兩個 closure gate

以下的 Laravel example code 的意思是?

  • Example:
<?php
if (Gate::none(['update-post', 'delete-post'], $post)) {
// The user cannot update or delete the post
}
  • Answer: 判斷當前 authenticated user 是否 皆不被允許 update $post 以及 delete $post, 會執行 update-post 以及 delete-post closure gate

# Authorizing Or Throwing Exceptions

以下的 Laravel example code 的意思是?

  • Example:
<?php
Gate::authorize('update-post', $post);

// The action is authorized...
  • Answer: 當 current authenticated user 不具有 update-post 的權限時, throw 403 exception

以下的 Laravel example code 的意思是?

  • Example:
<?php
if (Gate::check('create-post', [$category, $extraFlag])) {
// The user can create the post...
}
  • Answer: 判斷當前 authenticated user 是否 被允許 create posts, 可使用 array 帶入複數的 parameters

# Gate Responses

以下的 Laravel example code 的意思是?

  • Example:
<?php
use Illuminate\Auth\Access\Response;
use Illuminate\Support\Facades\Gate;

Gate::define('edit-settings', function ($user) {
return $user->isAdmin
? Response::allow()
: Response::deny('You must be a super administrator.');
});
  • Answer: 定義一個名為 ‘edit-settings’ 的 gate, 套用後, 如果 $user 為 admin 就允許, 如果不是則 deny 並 return deny message

以下的 Laravel example code 的意思是?

  • Example:
<?php
$response = Gate::inspect('edit-settings', $post);

if ($response->allowed()) {
// The action is authorized...
} else {
echo $response->message();
}
  • Answer: 取得 Gate 回傳的完整 authorization response

# Intercepting Gate Checks

以下的 Laravel example code 的意思是?

  • Example:
<?php
Gate::before(function ($user, $ability) {
if ($user->isSuperAdmin()) {
return true;
}
});
  • Answer: 訂一個規則, 會在執行所有 Gate rule 之前先執行它, 比如說我要讓 superAdmin 有所有的權限

以下的 Laravel example code 的意思是?

  • Example:
<?php
Gate::after(function ($user, $ability, $result, $arguments) {
if ($user->isSuperAdmin()) {
return true;
}
});
  • Answer: 會在所有的 gate rule 執行完畢後, 才會執行 after 內定義的規則, 比如說, 我要先驗證一些必要驗證, 最後在驗證該使用者是否為 admin

# Creating Policies

# Generating Policies

Laravel Authentication 中, 使用 CLI 建立的 policy 會位於哪裡?

app/Policies 資料夾

以下的 Laravel example command 的意思是?

  • Example:
php artisan make:policy PolicyName --model=ModelName
  • Answer: 使用 CLI 建立一個 policy 並且指定 model

# Registering Policies

Laravel Authentication 中, 當我建立了 policy 之後, 我需要在哪一個檔案中註冊它

AuthServiceProvider.php

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Providers;

use App\Policies\PostPolicy;
use App\Post;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
protected $policies = [
Post::class => PostPolicy::class,
];

public function boot()
{
$this->registerPolicies();

//
}
}
  • Answer: 在 AuthServiceProvider 的 policies property 中給 model 註冊 policy

# Policy Auto-Discovery

Laravel Authentication 中, 如果我不想要每次都手動註冊 policy, 我想要使用 Laravel 預設的 auto-discovery, 假設 model name 為 User, 那該 Policy name 須為?

UserPolicy

以下的 Laravel example code 的意思是?

  • Example:
<?php
use Illuminate\Support\Facades\Gate;

Gate::guessPolicyNamesUsing(function ($modelClass) {
// return policy class name...
});
  • Answer: Laravel 預設的 auto-discovery 的 convention 為 modelNamePolicyName, 假如 model 為 User, 那符合 auto-discovery 的命名規則為 UserPolicy 可在 AuthServiceProviderboot(), 使用 Gate::guessPolicyNamesUsing method 變更預設的 convention

Laravel Authentication 中, 當我同時使用手動註冊 policy 以及 auto-discovery policy 時, 哪一個的優先順序較高?

手動註冊

# Writing Policies

# Policy Methods

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Policies;

use App\Post;
use App\User;

class PostPolicy
{
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
  • Answer: 定義 PostPolicy 的 update method, 定義 user 是否有 update 該 post 的權限

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Policies;

use App\Post;
use App\User;

class PostPolicy
{
public function update(User $user, Post $post)
{
return $user->id === $post->user_id;
}
}
  • Answer: 在 PostPolicy class, update method 中定義 $user 是否被允許 update $post

# Policy Responses

以下的 Laravel example code 的意思是?

  • Example:
<?php
use Illuminate\Auth\Access\Response;

public function update(User $user, Post $post)
{
return $user->id === $post->user_id
? Response::allow()
: Response::deny('You do not own this post.');
}
  • Answer:
<?php
// 在 policy class 中, 定義 允許, 不被允許 的 response
use Illuminate\Auth\Access\Response;

public function update(User $user, Post $post)
{
return $user->id === $post->user_id
// 允許則回覆 boolean true
? Response::allow()
// 不允許則回傳 403, message
: Response::deny('You do not own this post.');
}

Laravel Authentication 中, 根據官方文件描述, 我可以使用 Gate::inspect method 來取得 policy 的 authorization response 嗎?

可以

# Methods Without Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
// 在 policy class 中
public function create(User $user)
{
//
}
  • Answer: 由於 create() 並不需要 model parameter, 因此使用 User $user 即可

# Guest Users

Laravel Authentication 中, 預設在 policy 以及 gate 如果沒有初始化一個 authenticated user 的話, authorization 會 return 什麼?

false

Laravel Authentication 中, 預設在 policy 以及 gate 如果沒有初始化一個 authenticated user 的話, 會 return false, 如果我想要讓沒有 authenticated user 也可以通過 authorization check 的話, 有哪兩種方式??

  • optional type hint
  • return null

# Policy Filters

以下的 Laravel example code 的意思是?

  • Example:
<?php
public function before($user, $ability)
{
return false;
}
  • Answer: 在執行所有 policy 之前會先執行 before, 換言之, 以上的 example 總是會 return false, 代表任何 policy 都不可能會驗證通過 比方說, 如果原本 $user->can('show', $post) 是 true, 加上上面的 example 之後, 就會 return false

Laravel Authentication 中, 當我在 policy 中定義一個 before method 時, 如果該 policy class 中沒有任何 method 被呼叫, 那 before method 會被呼叫嗎?

不會哦

# Authorizing Actions Using Polices

# Via The User Model

以下的 Laravel example code 的意思是?

  • Example:
<?php
if ($user->can('update', $post)) {
//
}
  • Answer: 使用 can() 判斷 $user 是否有 update $post 的權限, 會調用 PostPolicy

Laravel Authentication 中, 當我使用 can method 如下 example 時, 如果說我並沒有註冊這個 policy, 那 Laravel 會怎麼做?

尋找 closure based Gate

# Actions That Don’t Require Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
use App\Post;

if ($user->can('create', Post::class)) {
// Executes the "create" method on the relevant policy...
}
  • Answer: 使用 can() 驗證 $user 是否可以在 Post model 中, 有 create 的權限, 如果是 update 類型的 method 會需要帶入指定的 $model, 因為 create 是不需要帶入指定的 $model 的, 所以帶入 Post model 的完整 class name 即可

# Via Middleware

以下的 Laravel example code 的意思是?

  • Example:
<?php
use App\Post;

Route::put('/post/{post}', function (Post $post) {
// The current user may update the post...
})->middleware('can:update,post');
  • Answer: 使用 can middleware 驗證發 request 的 user 是否具有 update 該 post model 的權限, 第一個 arg 為 update 權限, 會執行 post policy 的 update method, 第二個 ‘post’ 為 url parameter 中帶入的該 post model, update method 會判斷該 user 是否有權限 update 該 post model

# Actions That Don’t Require Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
Route::post('/post', function () {
// The current user may create posts...
})->middleware('can:create,App\Post');
  • Answer: 使用 can middleware 驗證 $user 是否可以在 Post model 中, 有 create 的權限, 如果是 update 類型的 method 會需要帶入指定的 $model, 因為 create 是不需要帶入指定的 $model 的, 所以帶入 Post model 的完整 class name 即可

# Via Controller Helpers

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
public function update(Request $request, Post $post)
{
$this->authorize('update', $post);

// The current user can update the blog post...
}
}
  • Answer: 使用 authorize method, 會根據定義的 policy 判斷該 authenticated user 是否有 update 該 $post 的權限, 如果不允許, 會 throw 403

# Action That Don’t Require Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
public function create(Request $request)
{
$this->authorize('create', Post::class);

// The current user can create blog posts...
}
  • Answer: 使用 authorize(), 驗證 authenticated user 是否可以在 Post model 有 create 的操作權限, 該邏輯判斷定義在 PostPolicy, 若不可會直接 throw 403

# Authorizing Resource Controllers

以下的 Laravel example code 的意思是?

  • Example:
<?php

namespace App\Http\Controllers;

use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Http\Request;

class PostController extends Controller
{
public function __construct()
{
$this->authorizeResource(Post::class, 'post');
}
}
  • Answer: 在 controller 的 construct() 中使用 authorizeResource(), arg1 為 policy model class name, arg2 為 url parameter $post, 會自動將 authorize 套用到該 Resource Controller 中的每個 method

# Via Blade Templates

以下的 Laravel example code 的意思是?

  • Example:
<?php
@can('update', $post)
<!-- The Current User Can Update The Post -->
@elsecan('create', App\Post::class)
<!-- The Current User Can Create New Post -->
@endcan
  • Answer: 在 Blade 中判斷 current user 是否 被允許 update 該 $post 的權限, 驗證邏輯定義在 PostPolicy class

以下的 Laravel example code 的意思是?

  • Example:
<?php
@cannot('update', $post)
<!-- The Current User Cannot Update The Post -->
@elsecannot('create', App\Post::class)
<!-- The Current User Cannot Create A New Post -->
@endcannot
  • Answer: 在 Blade 中判斷 current user 是否 不被允許 update 該 $post 的權限, 是否 不被允許 在 Post model 執行 'create' 的操作, 驗證邏輯定義在 PostPolicy class

Laravel Authentication 中, 以下的 blade template example 實際上是什麼的縮寫?

  • Example:
<?php
@can('update', $post)
<!-- The Current User Can Update The Post -->
@endcan

@cannot('update', $post)
<!-- The Current User Cannot Update The Post -->
@endcannot
  • Answer:
<?php
@if (Auth::user()->can('update', $post))
<!-- The Current User Can Update The Post -->
@endif

@unless (Auth::user()->can('update', $post))
<!-- The Current User Cannot Update The Post -->
@endunless

以下的 Laravel example code 的意思是?

  • Example:
<?php
@canany(['update', 'view', 'delete'], $post)
// The current user can update, view, or delete the post
@elsecanany(['create'], \App\Post::class)
// The current user can create a post
@endcanany
  • Answer: 判斷 current user 是否 被允許 updateviewdelete $post model, 任意一項都算 判斷 current user 是否 被允許 在 Post model 中實施 create 的操作 以上的權限邏輯都定義在 PostPolicy

# Actions That Don’t Require Models

以下的 Laravel example code 的意思是?

  • Example:
<?php
@can('create', App\Post::class)
<!-- The Current User Can Create Posts -->
@endcan

@cannot('create', App\Post::class)
<!-- The Current User Can't Create Posts -->
@endcannot
  • Answer: 使用 Blade authorization method 判斷 current user 是否 被允許 對 Post model 操作 create 的權限 判斷 current user 是否 不被允許 對 Post model 操作 create 的權限 驗證邏輯會使用定義好的 policy

# Supplying Additional Context

Laravel Authentication 中, 在定義 policy 時, 如果除了 user 以及 model 之外, 我還要帶入額外的參數來驗證, 在以下的 example 中, 參數可以帶在哪?

  • Example:
<?php
public function update(User $user, Post $post, int $category)
{
return $user->id === $post->user_id &&
$category > 3;
}
  • Answer: 定義 PostPolicy, 若有需要可帶入多個 args

以下的 Laravel example code 的意思是?

  • Example:
<?php
public function update(Request $request, Post $post)
{
$this->authorize('update', [$post, $request->input('category')]);

// The current user can update the blog post...
}
  • Answer: 在 controller 的 update method 中, 使用 authorize() 來驗證 authenticated user 是否有 update 該 $post 的權限, 帶入兩個參數, 這兩個參數會被 pass 到 policy 或 closure based gate

--

--

Ray Lee | 李宗叡
Learn or Die

It's Ray. I do both backend and frontend, but more focus on backend. I like coding, and would like to see the whole picture of a product.