首頁 >後端開發 >php教程 >Laravel中的門與策略

Laravel中的門與策略

WBOY
WBOY原創
2023-08-31 13:49:061558瀏覽

Laravel中的門與策略

今天,我們將討論 Laravel Web 框架的授權系統。 Laravel 框架以閘和策略的形式實現授權。在介紹了門和策略之後,我將透過實作一個自訂範例來示範這些概念。

我假設您已經了解內建的 Laravel 身份驗證系統,因為這是理解授權概念所必需的。顯然,授權系統與認證系統一起工作來識別合法的使用者會話。

如果您不了解 Laravel 身份驗證系統,我強烈建議您閱讀官方文檔,它可以讓您深入了解該主題。

Laravel 的授權方法

現在,您應該已經知道 Laravel 授權系統有兩種形式:門和策略。雖然這聽起來像是一件複雜的事情,但我想說,一旦掌握了它的竅​​門,它就很容易實現!

Gate 讓您可以使用簡單的基於閉包的方法定義授權規則。換句話說,當您想要授權與任何特定模型無關的操作時,閘門是實現該邏輯的完美位置。

讓我們快速了解一下基於門的授權是什麼樣的:

...
...
Gate::define('update-post', function ($user, $post) {
  return $user->id == $post->user_id;
});
...
...

上面的程式碼片段定義了授權規則 update-post 您可以從應用程式中的任何位置呼叫它。

另一方面,當您想要對任何模型的授權邏輯進行分組時,您應該使用策略。例如,假設您的應用程式中有一個 Post 模型,並且您想要授權該模型的 CRUD 操作。在這種情況下,這就是您需要實施的策略。

class PostPolicy
{
  public function view(User $user, Post $post) {}
  public function create(User $user) {}
  public function update(User $user, Post $post) {}
  public function delete(User $user, Post $post) {}
}

如您所見,這是一個非常簡單的策略類,定義了 Post 模型的 CRUD 操作的授權。

這是 Laravel 中的門和策略的介紹。從下一節開始,我們將對每個元素進行實際示範。

大門

在本節中,我們將透過一個現實範例來理解門的概念。

如何建立自訂閘

當您需要註冊元件或服務時,您通常會尋找 Laravel 服務提供者。遵循該約定,讓我們繼續在 app/Providers/AuthServiceProvider.php 中定義自訂門,如以下程式碼片段所示。

<?php
namespace App\Providers;
 
use Illuminate\Support\Facades\Gate;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
 
class AuthServiceProvider extends ServiceProvider
{
  /**
   * The policy mappings for the application.
   *
   * @var array
   */
  protected $policies = [
    'App\Model' => 'App\Policies\ModelPolicy',
  ];
 
  /**
   * Register any authentication / authorization services.
   *
   * @return void
   */
  public function boot()
  {
    $this->registerPolicies();
     
    Gate::define('update-post', function ($user, $post) {
      return $user->id == $post->user_id;
    });
  }
}

boot 方法中,我們定義了自訂閘:

Gate::define('update-post', function ($user, $post) {
  return $user->id == $post->user_id;
});

定義閘時,它需要一個閉包,根據閘定義中定義的授權邏輯,傳回 TRUEFALSE 。除了閉包函數之外,還有其他方法可以定義閘。

例如,以下門定義呼叫控制器操作而不是閉包函數。

Gate::define('update-post', 'ControllerName@MethodName');

如何使用我們的自訂大門

現在,讓我們繼續新增自訂路由,以便我們可以示範基於閘門的授權如何運作。在路由檔案 routes/web.php 中,新增以下路由。

Route::get('service/post/gate', 'PostController@gate');

讓我們也建立一個關聯的控制器檔案app/Http/Controllers/PostController.php

<?php
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Support\Facades\Gate;
 
class PostController extends Controller
{
  /* Make sure you don't use Gate and Policy altogether for the same Model/Resource */
  public function gate()
  {
    $post = Post::find(1);
 
    if (Gate::allows('update-post', $post)) {
      echo 'Allowed';
    } else {
      echo 'Not Allowed';
    }
     
    exit;
  }
}

在大多數情況下,您最終會使用 allowsdenies 方法(Gate 外觀)來授權特定操作。在上面的範例中,我們使用 allows 方法來檢查目前使用者是否能夠執行 update-post 操作。

眼尖的使用者會注意到我們只將第二個參數 $post 傳遞給了閉包。第一個參數是目前登入的用戶,由 Gate 門面自動注入。

這就是您應該如何使用門來授權 Laravel 應用程式中的操作。如果您希望為模型實現授權,下一節將介紹如何使用策略。

政策

正如我們之前討論的,當您想要對任何特定模型或資源的授權操作進行邏輯分組時,您需要的就是策略。

如何建立自訂策略

在本節中,我們將為 Post 模型建立一個策略,用於授權所有 CRUD 操作。我假設您已經在應用程式中實現了 Post 模型;否則,類似的事情也會做。

Laravel artisan 指令是建立存根程式碼時最好的朋友。您可以使用以下 artisan 指令為 Post 模型建立策略。

$php artisan make:policy PostPolicy --model=Post

如您所見,我們提供了 --model=Post 參數,以便它可以建立所有 CRUD 方法。如果沒有,它將建立一個空白策略類別。您可以在 app/Policies/PostPolicy.php 中找到新建立的策略類別。

<?php

namespace App\Policies;

use App\Post;
use App\User;
use Illuminate\Auth\Access\HandlesAuthorization;

class PostPolicy
{
    use HandlesAuthorization;

    /**
     * Determine whether the user can view any models.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function viewAny(User $user)
    {
        //
    }

    /**
     * Determine whether the user can view the model.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return mixed
     */
    public function view(User $user, Post $post)
    {
        //
    }

    /**
     * Determine whether the user can create models.
     *
     * @param  \App\User  $user
     * @return mixed
     */
    public function create(User $user)
    {
        //
    }

    /**
     * Determine whether the user can update the model.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return mixed
     */
    public function update(User $user, Post $post)
    {
        //
    }

    /**
     * Determine whether the user can delete the model.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return mixed
     */
    public function delete(User $user, Post $post)
    {
        //
    }

    /**
     * Determine whether the user can restore the model.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return mixed
     */
    public function restore(User $user, Post $post)
    {
        //
    }

    /**
     * Determine whether the user can permanently delete the model.
     *
     * @param  \App\User  $user
     * @param  \App\Post  $post
     * @return mixed
     */
    public function forceDelete(User $user, Post $post)
    {
        //
    }
}

讓我們將其替換為以下程式碼。

<?php
namespace App\Policies;
 
use App\User;
use App\Post;
use Illuminate\Auth\Access\HandlesAuthorization;
 
class PostPolicy
{
  use HandlesAuthorization;
 
  /**
   * Determine whether the user can view the post.
   *
   * @param  \App\User  $user
   * @param  \App\Post  $post
   * @return mixed
   */
  public function view(User $user, Post $post)
  {
    return TRUE;
  }
 
  /**
   * Determine whether the user can create posts.
   *
   * @param  \App\User  $user
   * @return mixed
   */
  public function create(User $user)
  {
    return $user->id > 0;
  }
 
  /**
   * Determine whether the user can update the post.
   *
   * @param  \App\User  $user
   * @param  \App\Post  $post
   * @return mixed
   */
  public function update(User $user, Post $post)
  {
    return $user->id == $post->user_id;
  }
 
  /**
   * Determine whether the user can delete the post.
   *
   * @param  \App\User  $user
   * @param  \App\Post  $post
   * @return mixed
   */
  public function delete(User $user, Post $post)
  {
    return $user->id == $post->user_id;
  }
}

為了能夠使用我們的策略類,我們需要使用 Laravel 服務提供者註冊它,如以下程式碼片段所示。

<?php
namespace App\Providers;
 
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Http\Request;
use App\Post;
use App\Policies\PostPolicy;
 
class AuthServiceProvider extends ServiceProvider
{
  /**
   * The policy mappings for the application.
   *
   * @var array
   */
  protected $policies = [
    Post::class => PostPolicy::class
  ];
 
  /**
   * Register any authentication / authorization services.
   *
   * @return void
   */
  public function boot()
  {
    $this->registerPolicies();
  }
}

我們已在 $policies 屬性中新增了策略對應。它告訴 Laravel 呼叫對應的策略方法來授權 CRUD 操作。

您还需要使用 registerPolicies 方法注册策略,就像我们在 boot 方法中所做的那样。

没有模型的策略方法

PostPolicy 策略类中的 create 方法仅采用单个参数,这与采用两个参数的其他模型方法不同。一般来说,第二个参数是模型对象,您将在执行授权时使用它。但是,在 create 方法的情况下,您只需要检查是否允许相关用户创建新帖子。

在下一节中,我们将了解如何使用自定义策略类。

如何使用我们的自定义策略类

更进一步,让我们在 routes/web.php 文件中创建几个自定义路由,以便我们可以在那里测试我们的策略方法。

Route::get('service/post/view', 'PostController@view');
Route::get('service/post/create', 'PostController@create');
Route::get('service/post/update', 'PostController@update');
Route::get('service/post/delete', 'PostController@delete');

最后,让我们在 app/Http/Controllers/PostController.php 创建一个关联的控制器。

<?php
namespace App\Http\Controllers;
 
use App\Http\Controllers\Controller;
use App\Post;
use Illuminate\Support\Facades\Auth;
 
class PostController extends Controller
{
  public function view()
  {
    // get current logged in user
    $user = Auth::user();
     
    // load post
    $post = Post::find(1);
     
    if ($user->can('view', $post)) {
      echo "Current logged in user is allowed to update the Post: {$post->id}";
    } else {
      echo 'Not Authorized.';
    }
  }
 
  public function create()
  {
    // get current logged in user
    $user = Auth::user();
 
    if ($user->can('create', Post::class)) {
      echo 'Current logged in user is allowed to create new posts.';
    } else {
      echo 'Not Authorized';
    }
 
    exit;
  }
 
  public function update()
  {
    // get current logged in user
    $user = Auth::user();
 
    // load post
    $post = Post::find(1);
 
    if ($user->can('update', $post)) {
      echo "Current logged in user is allowed to update the Post: {$post->id}";
    } else {
      echo 'Not Authorized.';
    }
  }
 
  public function delete()
  {
    // get current logged in user
    $user = Auth::user();
     
    // load post
    $post = Post::find(1);
     
    if ($user->can('delete', $post)) {
      echo "Current logged in user is allowed to delete the Post: {$post->id}";
    } else {
      echo 'Not Authorized.';
    }
  }
}

您可以通过不同的方式使用策略来授权您的操作。在上面的示例中,我们使用 User 模型来授权我们的 Post 模型操作。

User 模型提供了两种有用的授权方法 — cancantcan 方法用于检查当前用户是否能够执行某个操作。而与 can 方法对应的 cant 方法,用于判断动作是否无法执行。

让我们从控制器中获取 view 方法的片段,看看它到底做了什么。

public function view()
{
  // get current logged in user
  $user = Auth::user();
   
  // load post
  $post = Post::find(1);
   
  if ($user->can('view', $post)) {
    echo "Current logged in user is allowed to update the Post: {$post->id}";
  } else {
    echo 'Not Authorized.';
  }
}

首先,我们加载当前登录的用户,这为我们提供了 User 模型的对象。接下来,我们使用 Post 模型加载示例帖子。

接下来,我们使用 User 模型的 can 方法来授权 Post 模型的 view 操作。 can 方法的第一个参数是您要授权的操作名称,第二个参数是您要授权的模型对象。

这是如何使用 User 模型通过策略授权操作的演示。或者,如果您在控制器中授权某个操作,则也可以使用控制器助手。

…
$this->authorize('view', $post);
…

如您所见,如果您使用控制器助手,则无需加载 User 模型。

如何通过中间件使用策略

或者,Laravel 还允许您使用中间件授权操作。让我们快速查看以下代码片段,了解如何使用中间件来授权模型操作。

Route::put('/post/{post}', function (Post $post) {
    // Currently logged-in user is allowed to update this post.... 
})->middleware('can:update,post');

在上面的示例中,它将使用 can 中间件。我们传递两个参数:第一个参数是我们想要授权的操作,第二个参数是路由参数。根据隐式模型绑定的规则,第二个参数会自动转换为 Post 模型对象,并作为第二个参数传递。如果当前登录的用户无权执行 update 操作,Laravel 将返回 403 状态代码错误。

如何将策略与刀片模板结合使用

如果您希望在登录用户被授权执行特定操作时显示代码片段,您还可以在刀片模板中使用策略。让我们快速看看它是如何工作的。

@can('delete', $post)
    <!-- Display delete link here... -->
@endcan

在上述情况下,它只会向有权对 Post 模型执行删除操作的用户显示删除链接。

这就是您可以使用的策略概念,在授权模型或资源时它非常方便,因为它允许您将授权逻辑分组在一个地方。

只需确保您不会将门和策略一起用于模型的相同操作,否则会产生问题。这就是我今天的内容,今天就到此为止!

结论

今天,Laravel 授权占据了我文章的中心位置。在文章的开头,我介绍了 Laravel 授权、网关和策略的主要要素。

接下来,我们创建了自定义门和策略,以了解它在现实世界中的工作原理。我希望您喜欢这篇文章,并在 Laravel 环境中学到了一些有用的东西。

对于刚刚开始使用 Laravel 或希望通过扩展来扩展您的知识、网站或应用程序的人,我们在 Envato Market 上提供了多种可供您学习的内容。

以上是Laravel中的門與策略的詳細內容。更多資訊請關注PHP中文網其他相關文章!

陳述:
本文內容由網友自願投稿,版權歸原作者所有。本站不承擔相應的法律責任。如發現涉嫌抄襲或侵權的內容,請聯絡admin@php.cn