Heim > PHP-Framework > Laravel > Hauptteil

Ein Artikel, um die Verwendung von Laravel Guards gründlich zu verstehen

藏色散人
Freigeben: 2021-12-07 15:57:36
nach vorne
3078 Leute haben es durchsucht

Laravel verfügt über eine der häufigsten Funktionen, nämlich die Authentifizierung dauerhafter Benutzer. In diesem Fall werden diese in jeder unterstützten Datenbank (MySQL, SQLite usw.) gespeichert, wenn man bedenkt, dass dies möglich ist. Dieses Zeug ist beim Einrichten erstaunlich eine Webanwendung und die Authentifizierung von Benutzern mit vergessenen Passwörtern und allen Optimierungen. Was passiert, wenn Sie etwas Komplexeres benötigen?

Was ist beispielsweise, wenn Sie mehrere Benutzertypen mit jeweils eigenem Authentifizierungsportal benötigen? Bei diesen verschiedenen Benutzertypen kann es sich um Kunden, Lieferanten und Administratoren handeln. Mechaniken wie diese können sehr schnell sehr verwirrend werden, das weiß ich, weil ich selbst dort gewesen bin. Normalerweise planen wir die Struktur der Datenbank im Voraus, aber nicht, wie unsere Authentifizierungsprozesse und -mechanismen aussehen werden.

Empfohlen: „Laravel-Tutorial

In diesem Artikel möchte ich aufschlüsseln und erklären, wie man mit diesen Szenarien umgeht.

Was sind Wachen?

Guards in Laravel sind ein Mechanismus, mit dem Ihre Anwendung erkennen kann, ob jemand oder sogar etwas authentifiziert ist. Wenn wir uns die Standardinstallation von Laravel ansehen, sehen wir normalerweise einen Wächter, bei dem es sich um ein Web handelt. Wenn sich ein Besucher über diesen Schutz authentifiziert, kann der Benutzer bei jeder Verwendung der Authentifizierungs-Middleware die Seite anzeigen, da der Standardschutz immer „Web“ ist. Wenn eine Person gerade surft und zu keinem Zeitpunkt authentifiziert ist, wird sie als Gast in dieser Wache bezeichnet.

Wenn einer Webanwendung zusätzlicher Schutz hinzugefügt wird, wird normalerweise ein anderer Authentifizierungsmechanismus für die API bereitgestellt, beispielsweise Benutzertokens. Dieser Standardschutz muss jedoch nicht der einzige Web-Schutz in Ihrer Anwendung sein. Tatsächlich können wir einen Guard für verschiedene Benutzertypen einrichten, auch für diejenigen, die sich nicht mit herkömmlichen Benutzernamen und Passwörtern authentifizieren.

Wie erstelle ich einen neuen Authenticatable for Eloquent-Anbieter?

Um zu demonstrieren, wie ein neues Authentifizierungsobjekt erstellt wird, verwenden wir ein Beispiel einer Seite, über die sich Kunden von Bestellungen authentifizieren können. Kunden können sich bei der Anwendung nur über eine signierte URL authentifizieren und nach der Authentifizierung andere Aktionen ausführen, beispielsweise eine Bestellung stornieren.

Zuerst erstellen wir ein neues Modell:

php artisan make:model Order
Nach dem Login kopieren

Jetzt müssen wir das Bestellmodell in app/Models/Order.php ändern und einige Schnittstellen und Eigenschaften hinzufügen. Dies erfüllt das Order-Modell, das mit Guards und Eloquent Provider-Typen verwendet werden kann.

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);
    }
}
Nach dem Login kopieren

Bitte beachten Sie, dass wir im Vergleich zum standardmäßigen User-Modell einfach die User-Klasse des Frameworks erweitern können, aber da wir keine Passwörter verwenden werden, werden wir sie ignorieren in der Lage sein, das Modell, dessen Passwort festgelegt wurde, erneut zu verwenden.

Sobald dies erledigt ist, müssen wir unseren Schutz zur Authentifizierungskonfiguration in configs/auth.php hinzufügen. Da wir auch ein anderes Modell verwenden, müssen wir einen zusätzlichen Anbieter implementieren, den wir Auftragsanbieter nennen, der vom Client Guard verwendet wird.

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',
        // ],
    ],
];
Nach dem Login kopieren

Das war's, unser neuer Wächter ist jetzt authentifiziert, aber wir brauchen einen Mechanismus, um Besucher zu authentifizieren, ohne dass ein Passwort erforderlich ist.

Erfordert die Authentifizierung ein Passwort?

Technisch gesehen ist für die Authentifizierung ein Passwort erforderlich, da es Teil der LightmateContractsAuthAuthenticatable-Schnittstelle ist, die eine Implementierung von getAuthPassword() erfordert. Im vorherigen Beispiel haben wir das Merkmal Authenticatable verwendet, um die Implementierung bereitzustellen. Dieser Code wird jedoch nur verwendet, wenn wir versuchen, die try-Methode des Wächters zu verwenden, die wir nicht verwenden werden.

In diesem Fall haben wir nicht vor, unsere Bestellung per E-Mail und Passwort zu verifizieren, sodass wir uns darüber keine Sorgen machen müssen. Stattdessen erstellen wir einfach eine neue Middleware-Komponente, die die Authentifizierung über eine signierte URL übernimmt, die nur unsere Anwendung generieren kann, damit Verkäufer sie den Kunden zur Verfügung stellen können.

Zuerst richten wir in routes/web.php eine Beispielroute für unsere Bestellung ein.

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',
    ]);
Nach dem Login kopieren

Bitte beachten Sie, dass wir eine authentifizierte Middleware hinzugefügt haben. Es existiert noch nicht, also müssen wir eines erstellen und es dem http-Kern hinzufügen. Wir können Middleware mit dem folgenden Befehl erstellen:

php artisan make:middleware AuthenticateWhenRequestIsSigned
Nach dem Login kopieren

这将创建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);
    }
}
Nach dem Login kopieren

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

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内核的其余部分
}
Nach dem Login kopieren

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

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

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,
    ];
}
Nach dem Login kopieren

我们可以通过向内核添加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
Nach dem Login kopieren

现在,由于模型和可验证的匹配,我们需要重命名几个方法的参数,并为这些方法分配一个返回值,这将允许订单只查看和更新它自己。我们需要继续编辑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;
    }
}
Nach dem Login kopieren

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

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 的其余部分
}
Nach dem Login kopieren

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

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'
    ]);
Nach dem Login kopieren

将 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',
        // ],
    ],
];
Nach dem Login kopieren

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

结论

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

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

Originaladresse: https://dev.to/slyfirefox/laravel-authentication-understanding-guards-and-implementing-authenticatables-2364

Übersetzungsadresse: https://learnku.com/laravel/t/63367

Das obige ist der detaillierte Inhalt vonEin Artikel, um die Verwendung von Laravel Guards gründlich zu verstehen. Für weitere Informationen folgen Sie bitte anderen verwandten Artikeln auf der PHP chinesischen Website!

Verwandte Etiketten:
Quelle:learnku.com
Erklärung dieser Website
Der Inhalt dieses Artikels wird freiwillig von Internetnutzern beigesteuert und das Urheberrecht liegt beim ursprünglichen Autor. Diese Website übernimmt keine entsprechende rechtliche Verantwortung. Wenn Sie Inhalte finden, bei denen der Verdacht eines Plagiats oder einer Rechtsverletzung besteht, wenden Sie sich bitte an admin@php.cn
Beliebte Tutorials
Mehr>
Neueste Downloads
Mehr>
Web-Effekte
Quellcode der Website
Website-Materialien
Frontend-Vorlage