ホームページ  >  記事  >  PHPフレームワーク  >  Laravel Guardsの使い方を徹底的に理解するための1つの記事

Laravel Guardsの使い方を徹底的に理解するための1つの記事

藏色散人
藏色散人転載
2021-12-07 15:56:513092ブラウズ

Laravel には最も一般的な機能の 1 つがあり、それは永続ユーザーを認証することです。この場合、永続ユーザーはサポートされているデータベース (MySQL、SQLite など) に保存されます。 Web アプリを数分でセットアップし、パスワードを忘れたユーザーを認証したり、あらゆる調整を行ったりすることに関しては、驚くべきものです。もっと複雑なものが必要な場合はどうなるでしょうか?

たとえば、独自の認証ポータルを持つ複数のユーザー タイプが必要な場合はどうすればよいでしょうか?これらのさまざまなタイプのユーザーは、顧客、ベンダー、管理者になることができます。このような仕組みはすぐに非常に混乱する可能性があることは、私も現場にいたことがあるのでよくわかります。通常、データベースの構造は事前に計画しますが、認証プロセスやメカニズムがどのようになるかは計画しません。

推奨: "laravel チュートリアル "

この記事では、これらのシナリオの処理方法を詳細に分けて説明したいと思います。

ガードとは何ですか?

Laravel のガードは、アプリケーションが誰か、または 何か が認証されているかどうかを知ることができるメカニズムです。 Laravel のデフォルトのインストールを見ると、通常、Web であるガードが表示されます。訪問者がこのガードを介して認証すると、デフォルトのガードは常に Web であるため、認証ミドルウェアを使用すると、ユーザーはページを表示できます。閲覧していて認証されない人は、そのガードではゲストと呼ばれます。

通常、Web アプリケーションに追加の保護手段を追加すると、ユーザー トークンなど、API に別の認証メカニズムが提供されます。ただし、このデフォルト ガードがアプリケーション内の唯一の Web ガードである必要はありません。実際、従来のユーザー名とパスワードを使用して認証しないユーザーも含め、さまざまなユーザー タイプに対して Guard を設定できます。

Eloquent プロバイダー用に新しい Authenticatable を作成するにはどうすればよいですか?

新しい Authenticatable を作成する方法を示すために、注文の顧客が認証できるページの例を使用します。顧客は署名付き URL を使用してのみアプリケーションに対して認証でき、認証されると、注文のキャンセルなどの他のアクションを実行できます。

まず、新しいモデルを作成します:

php artisan make:model Order

次に、app/Models/Order.php の Order モデルを変更し、いくつかの を追加する必要があります。インターフェイス traits。これは、ガード タイプと Eloquent プロバイダー タイプで使用できる順序モデルを満たします。

Order.php

<?php

namespace App\Models;

use Illuminate\Auth\Authenticatable;
use Illuminate\Auth\MustVerifyEmail;
use Illuminate\Contracts\Auth\Access\Authorizable as AuthorizableContract;
use Illuminate\Contracts\Auth\Authenticatable as AuthenticatableContract;
use Illuminate\Database\Eloquent\Model;
use Illuminate\Database\Eloquent\Relations\BelongsTo;
use Illuminate\Foundation\Auth\Access\Authorizable;

class Order extends Model implements
    AuthenticatableContract,
    AuthorizableContract
{
    use Authenticatable;
    use Authorizable;
    use MustVerifyEmail;

    public function user(): BelongsTo
    {
        return $this->belongsTo(User::class);
    }
}

すぐに使える User モデルと比較して、フレームワークの User## を単純に拡張できることに注意してください。 # クラスですが、パスワードを使用するつもりはないので、パスワードをリセットできるモデルは無視します。

これを完了したら、

configs/auth.php の認証構成に保護を追加する必要があります。別のモデルも使用しているため、クライアント ガードが使用する追加のプロバイダー (オーダー プロバイダーと呼びます) を実装する必要があります。

auth.php

<?php
return [
    // auth.php 配置的其余部分

    &#39;guards&#39; => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'customer' => [
            'driver' => 'session',
            'provider' => 'orders',
        ],
    ],

    // auth.php 配置的其余部分
    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

        'orders' => [
            'driver' => 'eloquent',
            'model' => App\Models\Order::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],
];
これで、新しいガードは認証されましたが、パスワードを要求せずに訪問者を認証するメカニズムが必要です。

認証にはパスワードが必要ですか?

技術的には、はい、認証にはパスワードが必要です。認証は Lightmate\Contracts\Auth\Authenticatable インターフェイスの一部であるため、このインターフェイスにはパスワードが必要です。 getAuthPassword() の実装。前の例では、Authenticatable トレイトを使用して実装を提供しました。ただし、このコードは、ガードの try メソッドを使用しようとする場合にのみ使用されますが、このメソッドは使用しません。

この場合、メールとパスワードで注文を確認する予定はありませんので、心配する必要はありません。代わりに、販売者が顧客に提供するためにアプリケーションのみが生成できる署名付き URL からの認証を処理する新しい

Middleware コンポーネントを作成します。

まず、注文のサンプルルートを

routes/web.php に設定します。

web.php

<?php

use Illuminate\Support\Facades\Route;

Route::get(&#39;order/{order}&#39;, function (\App\Models\Order $order) {
    return view(&#39;order.view&#39;, [&#39;order&#39; => $order]);
})
    ->name('order.view')
    ->middleware([
        'auth.signed:order,customer',
        'auth:customer,seller',
    ]);
認証済みミドルウェアが追加されたことに注意してください。これはまだ存在しないため、作成して http コアに追加する必要があります。次のコマンドを使用してミドルウェアを作成できます:

php artisan make:middleware AuthenticateWhenRequestIsSigned

这将创建app/Http/Middleware/AuthenticateWhenRequestIsSigned.php文件,我们可以编辑该文件。我们将向Handle方法添加两个参数,这两个参数将是要从路由和我们想要进行身份验证的守卫中使用的参数名称。然后,Handle方法的代码非常简单,如果请求已签名,则使用Order参数中的ID值对客户进行身份验证。

AuthenticateWhenRequestIsSigned.php

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

class AuthenticateWhenRequestIsSigned
{
    public function handle(Request $request, Closure $next, string $parameterName, string $guard = null)
    {
        if ($request->hasValidSignature()) {
            if (Auth::guard($guard)->check()) {
                Auth::guard($guard)->logout();
            }
            Auth::guard($guard)->loginUsingId($request->route()->parameter($parameterName));
        }

        return $next($request);
    }
}

现在我们已经创建了中间件,我们需要在内核中注册它。

Kernel.php

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    // Http内核的其余部分

    /**
     * 应用程序的路由中间件。
     *
     * 这些中间件可以分配到组中,也可以单独使用。
     *
     * @var array
     */
    protected $routeMiddleware = [
        // 数组的其余部分
        &#39;auth.signed&#39; => \App\Http\Middleware\AuthenticateWhenRequestIsSigned::class,
        // 数组的其余部分
    ];

    // Http内核的其余部分
}

这样做不会使中间件工作,因为我们还将身份验证中间件用于我们的路由,这意味着身份验证签名的中间件永远不会执行,因为身份验证中间件具有优先级,并且将在签名中间件有机会对客户进行身份验证之前终止请求。

要解决这个问题,我们只需要向内核添加一个额外的数组,以设置在会话启动中间件之后运行的身份验证签名中间件的优先级。

Kernel.php

<?php

namespace App\Http;

use Illuminate\Foundation\Http\Kernel as HttpKernel;

class Kernel extends HttpKernel
{
    // HTTP内核的其余部分

    /**
     * 中间件的优先级排序列表。
     *
     * 强制非全局中间件始终处于给定顺序。
     *
     * @var string[]
     */
    protected $middlewarePriority = [
        \Illuminate\Cookie\Middleware\EncryptCookies::class,
        \Illuminate\Session\Middleware\StartSession::class,
        \Illuminate\View\Middleware\ShareErrorsFromSession::class,
        \App\Http\Middleware\AuthenticateWhenRequestIsSigned::class,
        \Illuminate\Contracts\Auth\Middleware\AuthenticatesRequests::class,
        \Illuminate\Routing\Middleware\ThrottleRequests::class,
        \Illuminate\Routing\Middleware\ThrottleRequestsWithRedis::class,
        \Illuminate\Session\Middleware\AuthenticateSession::class,
        \Illuminate\Routing\Middleware\SubstituteBindings::class,
        \Illuminate\Auth\Middleware\Authorize::class,
    ];
}

我们可以通过向内核添加midlewarePriority属性来实现这一点,覆盖父级Kernel。在AuthenticatesRequests中间件和StartSession中间件之前这样做意味着,当URL中提供有效签名时,中间件可以对客户进行身份验证。

现在,每当访问者使用带有有效签名的url登陆该页面时,他们将通过我们的守卫进行身份验证,并能够在没有签名的情况下重新访问该url,直到他们的会话超时。不过,这仍然有一个问题,任何这样做的客户也不仅能够查看他们的订单,还可以通过简单地更改URL中的id来查看任何订单。请记住,Authentication不是Authorization,这意味着为了保护客户的其他订单,我们需要添加一些授权。

我们如何保护客户只看到一个订单?

这是一个相当简单的程序。我们现在只需要一个策略,但在本例中,我们需要使用guard参数作为policy make命令的一部分。这将允许我们生成我们需要的大部分代码。

php artisan make:policy --guard customer --model App/Models/Order CustomerOrderPolicy

现在,由于模型和可验证的匹配,我们需要重命名几个方法的参数,并为这些方法分配一个返回值,这将允许订单只查看和更新它自己。我们需要继续编辑app/policies/customerOrderPolicy.php。我们实现了用于updatingviewing单个订单的方法,其余的可以返回false。

CustomerOrderPolicy.php

<?php

namespace App\Policies;

use App\Models\Order;
use Illuminate\Auth\Access\HandlesAuthorization;

class CustomerOrderPolicy
{
    use HandlesAuthorization;

    public function viewAny(Order $order)
    {
        return false;
    }

    public function view(Order $customer, Order $order)
    {
        return $customer->is($order);
    }

    public function create(Order $order)
    {
        return false;
    }

    public function update(Order $customer, Order $order)
    {
        return $customer->is($order);
    }

    public function delete(Order $customer, Order $order)
    {
        return false;
    }

    public function restore(Order $customer, Order $order)
    {
        return false;
    }

    public function forceDelete(Order $customer, Order $order)
    {
        return false;
    }
}

一旦我们完成了这一点,我们只需要注册策略并将中间件添加到路由中。现在,当经过身份验证的用户试图访问除他们自己的订单之外的任何订单时,他们都将失败。这样,我们就通过对用户的身份验证和授权保护了应用程序。

AuthServiceProvider.php

<?php

namespace App\Providers;

use App\Models\Order;
use App\Policies\CustomerOrderPolicy;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Gate;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * 应用程序的策略映射.
     *
     * @var array
     */
    protected $policies = [
        Order::class => CustomerOrderPolicy::class,
    ];

    // AuthServiceProvider 的其余部分
}

现在,我们通过配置路由查看订单的策略。

web.php

<?php

use Illuminate\Support\Facades\Route;

Route::get(&#39;order/{order}&#39;, function (\App\Models\Order $order) {
    return view(&#39;order.view&#39;, [&#39;order&#39; => $order]);
})
    ->name('order.view')
    ->middleware([
        'auth.signed:order,customer',
        'auth:customer,seller',
        'can:view,order'
    ]);

将 Web Guard 重命名为更具描述性的东西有多难?

只有当我们也有一名称为卖家的守卫时,让一名称为客户的守卫才真正有意义,他们仍然会使用电子邮件和密码进行身份验证,为客户生成订单。我们已经有了 web 守卫,但这并不是真正适合所有的 web 用户,而是为卖家准备的,所以我们会相应地给它命名。

重命名默认守卫可能会变得很棘手,特别是在其他中间件和包(如Laravel Sanctum和Fortify)将按名称使用 Web 守卫的情况下。幸运的是,这两个包都有配置选项,可以轻松地更改这一点。

首先,我们必须编辑 configs/auth.php 以拥有一个名为卖家的守卫。然后,我们还需要更新默认值以反映名称更改。

auth.php

<?php
return [
    // auth.php 其余的配置部分

    &#39;guards&#39; => [
        'web' => [
            'driver' => 'session',
            'provider' => 'users',
        ],

        'customer' => [
            'driver' => 'session',
            'provider' => 'orders',
        ],
    ],

    // auth.php 其余的配置部分

    'providers' => [
        'users' => [
            'driver' => 'eloquent',
            'model' => App\Models\User::class,
        ],

        'orders' => [
            'driver' => 'eloquent',
            'model' => App\Models\Order::class,
        ],

        // 'users' => [
        //     'driver' => 'database',
        //     'table' => 'users',
        // ],
    ],
];

如果我们还使用 Fortify 和 Sanctum 那么每个配置都需要设置一个 guard ,该值将为这些包配置保护. 之后就可以使用了. 需要用 auth:seller 替代 auth:web 更新路由 。

结论

与 Guards 一起工作一开始可能会有点混乱,在做出长期决定之前肯定需要一些探索。我曾在多个项目中工作过,在这些项目中,分离警卫既是有益的,也是一种负担。通常,处理这种情况的最佳方法是构建一个快速原型,说明如何处理某些分离。通常,在决定访问者是否可以访问网站的特定部分时,使用 Gate  是一个更好的选择。

我已经简单介绍了本文中的所有步骤,如果您希望进行更多的实验或了解此工作流的实际工作方式,您可以从 github repository 克隆设置好的代码,在演示代码中包含了一个测试,如果您想进一步进行实验,可以使用它。

元のアドレス: https://dev.to/slyfirefox/laravel-authentication- Understanding-guards-and-implementing-authenticatables-2364

翻訳アドレス: https://learnku.com /laravel/t/63367

以上がLaravel Guardsの使い方を徹底的に理解するための1つの記事の詳細内容です。詳細については、PHP 中国語 Web サイトの他の関連記事を参照してください。

声明:
この記事はlearnku.comで複製されています。侵害がある場合は、admin@php.cn までご連絡ください。