Rumah  >  Artikel  >  rangka kerja php  >  Satu artikel untuk memahami secara menyeluruh penggunaan Pengawal Laravel

Satu artikel untuk memahami secara menyeluruh penggunaan Pengawal Laravel

藏色散人
藏色散人ke hadapan
2021-12-07 15:56:513072semak imbas

Laravel mempunyai salah satu ciri yang paling biasa, iaitu untuk mengesahkan pengguna yang berterusan, dalam hal ini ia disimpan dalam mana-mana pangkalan data yang disokong (MySQL, SQLite, dll.), dan apabila anda menganggap bahawa anda boleh Perkara ini adalah menakjubkan apabila menyediakan apl web dalam beberapa minit dan mengesahkan pengguna dengan kata laluan yang terlupa dan semua tweak. Apa yang berlaku apabila anda memerlukan sesuatu yang lebih kompleks?

Sebagai contoh, bagaimana jika anda memerlukan berbilang jenis pengguna dengan portal pengesahan mereka sendiri? Jenis pengguna yang berbeza ini boleh menjadi pelanggan, vendor dan pentadbir. Mekanik seperti ini boleh menjadi sangat mengelirukan dengan cepat, saya tahu kerana saya pernah ke sana. Kami biasanya pra-merancang struktur pangkalan data tetapi bukan rupa proses dan mekanisme pengesahan kami.

Disyorkan: "tutorial laravel"

Dalam artikel ini, saya berharap untuk memecahkan dan menerangkan cara mengendalikan senario ini.

Apakah Pengawal?

Pengawal dalam Laravel ialah mekanisme yang dengannya aplikasi anda boleh mengetahui sama ada seseorang atau pun sesuatu disahkan. Apabila kita melihat pada pemasangan lalai Laravel, kita biasanya melihat pengawal, iaitu web. Apabila pelawat mengesahkan melalui pengawal ini, sebarang penggunaan perisian tengah auth akan membolehkan pengguna melihat halaman kerana pengawal lalai di luar kotak sentiasa web. Jika seseorang sedang menyemak imbas dan tidak disahkan pada bila-bila masa, mereka dipanggil tetamu dalam pengawal itu.

Selalunya apabila menambah perlindungan tambahan pada aplikasi web, ia menyediakan mekanisme pengesahan yang berbeza untuk API, seperti token pengguna. Walau bagaimanapun, pengawal lalai ini tidak perlu menjadi satu-satunya pengawal web dalam aplikasi anda. Malah, kami boleh menyediakan Pengawal untuk jenis pengguna yang berbeza, malah mereka yang tidak mengesahkan menggunakan nama pengguna dan kata laluan tradisional.

Bagaimana untuk mencipta pembekal Boleh Sahih untuk Eloquent baharu?

Untuk menunjukkan cara mencipta Boleh Sahih baharu, kami akan menggunakan contoh halaman yang melaluinya pelanggan pesanan boleh mengesahkan. Pelanggan hanya boleh mengesahkan aplikasi menggunakan URL yang ditandatangani dan setelah disahkan, mereka boleh melakukan tindakan lain, seperti membatalkan pesanan.

Pertama, kami mencipta model baharu:

php artisan make:model Order

Sekarang, kami perlu mengubah suai model Pesanan dalam app/Models/Order.php dan menambah beberapa antara muka dan ciri. Ini memenuhi model Pesanan yang boleh digunakan dengan pengawal dan jenis pembekal Fasih.

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);
    }
}

Sila ambil perhatian bahawa berbanding model Pengguna yang luar biasa, kami hanya boleh melanjutkan Pengguna rangka kerja kelas , tetapi kerana kami tidak akan menggunakan kata laluan, kami akan mengabaikan model yang dapat menetapkan semula kata laluannya.

Setelah ini selesai, kami perlu menambah perlindungan kami pada konfigurasi pengesahan dalam configs/auth.php. Kerana kami juga menggunakan model yang berbeza, kami perlu melaksanakan pembekal tambahan, yang akan kami panggil pembekal pesanan, untuk digunakan oleh pengawal pelanggan.

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

Itu sahaja, pengawal baharu kami kini disahkan, tetapi kami memerlukan mekanisme untuk mengesahkan pelawat tanpa memasukkan kata laluan.

Adakah pengesahan memerlukan kata laluan

Secara teknikal, ya, pengesahan memerlukan kata laluan kerana ia adalah sebahagian daripada antara muka LightmateContractsAuthAuthenticatable yang memerlukan pelaksanaan getAuthPassword(). Dalam contoh sebelumnya, kami menggunakan sifat Boleh Sahih untuk menyediakan pelaksanaan. Walau bagaimanapun, kod ini hanya akan digunakan jika kami cuba menggunakan kaedah percubaan pengawal, yang kami tidak akan gunakan.

Dalam kes ini, kami tidak bercadang untuk mengesahkan pesanan kami melalui e-mel dan kata laluan, jadi kami tidak perlu risau tentang perkara itu. Sebaliknya, kami hanya akan mencipta komponen Perisian Tengah baharu yang akan mengendalikan pengesahan daripada URL yang ditandatangani yang hanya aplikasi kami boleh menjana untuk penjual berikan kepada pelanggan.

Pertama, kami akan menyediakan laluan sampel untuk pesanan kami dalam laluan/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',
    ]);

Sila ambil perhatian bahawa kami telah menambah perisian tengah yang disahkan. Ia belum wujud lagi, jadi kita perlu mencipta satu dan menambahnya pada teras http. Kita boleh mencipta middleware menggunakan arahan berikut:

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 克隆设置好的代码,在演示代码中包含了一个测试,如果您想进一步进行实验,可以使用它。

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

Alamat terjemahan: https://learnku.com /laravel/t/63367

Atas ialah kandungan terperinci Satu artikel untuk memahami secara menyeluruh penggunaan Pengawal Laravel. Untuk maklumat lanjut, sila ikut artikel berkaitan lain di laman web China PHP!

Kenyataan:
Artikel ini dikembalikan pada:learnku.com. Jika ada pelanggaran, sila hubungi admin@php.cn Padam