>PHP 프레임워크 >Laravel >Laravel Guards의 사용법을 철저하게 이해하기 위한 하나의 기사

Laravel Guards의 사용법을 철저하게 이해하기 위한 하나의 기사

藏色散人
藏色散人앞으로
2021-12-07 15:56:513130검색

Laravel에는 영구 사용자를 인증하는 가장 일반적인 기능 중 하나가 있으며, 이 경우 지원되는 모든 데이터베이스(MySQL, SQLite 등)에 저장됩니다. 설정할 때 이 기능은 놀랍습니다. 웹 애플리케이션을 만들고 잊어버린 비밀번호와 모든 조정을 통해 사용자를 인증합니다. 더 복잡한 것이 필요할 때는 어떻게 되나요?

예를 들어, 자체 인증 포털을 통해 여러 사용자 유형이 필요한 경우 어떻게 해야 합니까? 이러한 다양한 유형의 사용자는 고객, 공급업체 및 관리자일 수 있습니다. 이와 같은 메커니즘은 매우 빠르게 매우 혼란스러울 수 있습니다. 저도 거기에 가본 적이 있기 때문에 압니다. 우리는 일반적으로 데이터베이스의 구조를 미리 계획하지만 인증 프로세스와 메커니즘이 어떤 모습일지는 미리 계획하지 않습니다.

추천: "laravel tutorial"

이 기사에서는 이러한 시나리오를 분석하고 처리하는 방법을 설명하고자 합니다.

경비원이란 무엇인가요?

Laravel의 Guard는 애플리케이션이 누군가 또는 심지어 무언가가 인증되었는지 여부를 알 수 있는 메커니즘입니다. Laravel의 기본 설치를 살펴보면 일반적으로 웹이라는 가드를 볼 수 있습니다. 방문자가 이 가드를 통해 인증할 때 기본 가드는 항상 웹이므로 인증 미들웨어를 사용하면 사용자가 페이지를 볼 수 있습니다. 어떤 사람이 브라우징 중이고 언제든지 인증되지 않으면 해당 가드에서는 게스트라고 합니다.

일반적으로 웹 애플리케이션에 추가 보호를 추가할 때 사용자 토큰과 같은 API에 대한 다른 인증 메커니즘을 제공합니다. 그러나 이 기본 가드가 애플리케이션의 유일한 웹 가드일 필요는 없습니다. 실제로 다양한 사용자 유형에 대해 Guard를 설정할 수 있습니다. 기존 사용자 이름과 비밀번호를 사용하여 인증하지 않는 사용자도 마찬가지입니다.

Eloquent 공급자에 대한 새로운 인증 가능 파일을 만드는 방법은 무엇입니까?

새 인증 가능 항목을 생성하는 방법을 보여주기 위해 주문 고객이 인증할 수 있는 페이지의 예를 사용하겠습니다. 고객은 서명된 URL을 통해서만 애플리케이션에 인증할 수 있으며, 인증을 받은 후에는 주문 취소와 같은 다른 작업을 수행할 수 있습니다.

먼저 새 모델을 만듭니다.

php artisan make:model Order

이제 app/Models/Order.php에서 Order 모델을 수정하고 interfacestraits을 추가해야 합니다. 이는 Guards 및 Eloquent 공급자 유형과 함께 사용할 수 있는 Order 모델을 충족합니다.

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',
        // ],
    ],
];

이제 새 경비원이 인증되었지만 비밀번호를 요구하지 않고 방문자를 인증할 수 있는 메커니즘이 필요합니다.

인증에는 비밀번호가 필요합니까?

기술적으로 인증에는 getAuthPassword() 구현이 필요한 LightmateContractsAuthAuthenticatable 인터페이스의 일부이므로 비밀번호가 필요합니다. 이전 예제에서는 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의 사용법을 철저하게 이해하기 위한 하나의 기사의 상세 내용입니다. 자세한 내용은 PHP 중국어 웹사이트의 기타 관련 기사를 참조하세요!

성명:
이 기사는 learnku.com에서 복제됩니다. 침해가 있는 경우 admin@php.cn으로 문의하시기 바랍니다. 삭제