一文彻底弄清Laravel Guards的使用

发布时间 - 2021-12-07 00:00:00    点击率:

laravel有一个最常见的功能,即对持久用户进行身份验证,在这种情况下, 这些功能存储在任何受支持的数据库 (mysql, sqlite 等),当你考虑到你可以在几分钟内设置一个web应用程序并使用忘记的密码和所有的调整进行用户身份验证时,这个东西是令人惊叹的。当你需要更复杂的东西时会发生什么?

例如,如果您需要拥有自己的身份验证门户的多个用户类型,该怎么办?这些不同类型的用户可以是客户、销售商和管理员。这样的机制可能很快就会变得非常混乱,我知道,因为我曾经经历过。我们通常预先计划数据库的结构,但不构建我们的身份验证流程和机制的样子。

推荐:《laravel教程》

在本文中,我希望分解并解释如何处理这些场景。

什么是 Guards?

Laravel 中的 Guards 是一种机制,您的应用程序可以通过它知道某人甚至某事是否经过身份验证。当我们查看 Laravel 的默认安装时,我们通常会看到一个守卫,即 web。当访问者通过此防护进行身份验证时,任何使用 auth 中间件都将允许用户通过查看页面,这是因为开箱即用的默认防护始终是 web。如果一个人正在浏览并且在任何时候都没有经过身份验证,那么他们在该守卫中被称为访客。

通常,当向 Web 应用程序添加额外的防护时,它会为 API 提供不同的身份验证机制,例如用户令牌。不过,这个默认守卫不必是您应用程序中唯一的 Web 守卫。事实上,我们可以为不同的用户类型设置一个 Guard,即使是那些不使用传统用户名和密码进行身份验证的用户。

如何为 Eloquent 提供程序创建新的 Authenticatable?

为了演示如何创建一个新的 Authenticatable,我们将使用一个页面示例,订单的客户可以通过该页面进行身份验证。 客户只能使用签名 URL 对应用程序进行身份验证,一旦通过身份验证,他们就可以执行其他操作,例如取消订单。

首先,我们创建一个新模型:

php artisan make:model Order

现在,我们需要修改 app/Models/Order.php 中的 Order 模型,添加一些 interfacestraits。 这满足 Order 模型可用于守卫和 Eloquent 提供者类型。

Order.php

belongsTo(User::class);
    }
}

请注意,与开箱即用的 User 模型相比,我们可以简单地扩展框架的 User 类,但由于我们不打算使用密码,所以我们将忽略能够重置其密码的模型。

完成此操作后,我们需要将我们的保护添加到 configs/auth.php 中的 auth 配置中。 因为我们也使用不同的模型,所以我们需要实现一个附加提供程序,我们将其称为订单提供程序,由客户守卫使用。

auth.php

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

就是这样,我们的新守卫现在已经通过了身份验证,但是我们需要一个机制来验证访问者,而不需要输入密码。

身份验证是否需要密码?

从技术上讲,是的, 身份验证需要密码,因为它是Lighmate\Contracts\Auth\Authenticatable接口的一部分,该接口需要getAuthPassword()的实现。在前面的示例中,我们使用了Authenticatable特征来提供实现。不过,只有当我们尝试使用守卫的尝试方法时,才会使用此代码,而我们不会使用此方法。

在这种情况下,我们没有计划通过电子邮件和密码来验证我们的订单,所以我们不必担心这一点。取而代之的是,我们将简单地创建一个新的中间件 组件,它将处理来自签名的URL的身份验证,只有我们的应用程序才能生成该URL供卖家提供给客户。

首先,我们将在routes/web.php中为我们的订单设置一个示例路由。

web.php

 $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

hasValidSignature()) {
            if (Auth::guard($guard)->check()) {
                Auth::guard($guard)->logout();
            }
            Auth::guard($guard)->loginUsingId($request->route()->parameter($parameterName));
        }

        return $next($request);
    }
}

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

Kernel.php

 \App\Http\Middleware\AuthenticateWhenRequestIsSigned::class,
        // 数组的其余部分
    ];

    // Http内核的其余部分
}

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

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

Kernel.php

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

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

 CustomerOrderPolicy::class,
    ];

    // AuthServiceProvider 的其余部分
}

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

web.php

 $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

 [
        '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  # 身份验证  # 应用程序  # 我们可以  # 卖家  # 创建一个  # 这样做  # 自己的  # 的是  # 当我们  # 他们的 


相关栏目: 【 网站优化151355 】 【 网络推广146373 】 【 网络技术251813 】 【 AI营销90571


相关推荐: 如何选择可靠的免备案建站服务器?  如何用腾讯建站主机快速创建免费网站?  Laravel如何与Pusher实现实时通信?(WebSocket示例)  如何在阿里云香港服务器快速搭建网站?  JavaScript中如何操作剪贴板_ClipboardAPI怎么用  车管所网站制作流程,交警当场开简易程序处罚决定书,在交警网站查询不到怎么办?  如何快速启动建站代理加盟业务?  Linux系统命令中screen命令详解  简单实现Android文件上传  手机钓鱼网站怎么制作视频,怎样拦截钓鱼网站。怎么办?  移动端脚本框架Hammer.js  Laravel如何实现邮件验证激活账户_Laravel内置MustVerifyEmail接口配置【步骤】  Laravel如何使用Service Provider服务提供者_Laravel依赖注入与容器绑定【深度】  简单实现Android验证码  韩国服务器如何优化跨境访问实现高效连接?  Laravel Facade的原理是什么_深入理解Laravel门面及其工作机制  HTML5空格和nbsp有啥关系_nbsp的作用及使用场景【说明】  LinuxCD持续部署教程_自动发布与回滚机制  如何用狗爹虚拟主机快速搭建网站?  Python文件流缓冲机制_IO性能解析【教程】  JavaScript如何实现继承_有哪些常用方法  Laravel如何集成Inertia.js与Vue/React?(安装配置)  进行网站优化必须要坚持的四大原则  Laravel如何实现API资源集合?(Resource Collection教程)  Laravel怎么配置自定义表前缀_Laravel数据库迁移与Eloquent表名映射【步骤】  laravel怎么配置Redis作为缓存驱动_laravel Redis缓存配置教程  CSS3怎么给轮播图加过渡动画_transition加transform实现【技巧】  Laravel Asset编译怎么配置_Laravel Vite前端构建工具使用  谷歌浏览器下载文件时中断怎么办 Google Chrome下载管理修复  Laravel如何使用缓存系统提升性能_Laravel缓存驱动和应用优化方案  Laravel项目结构怎么组织_大型Laravel应用的最佳目录结构实践  php做exe能调用系统命令吗_执行cmd指令实现方式【详解】  如何用搬瓦工VPS快速搭建个人网站?  HTML透明颜色代码怎么让下拉菜单透明_下拉菜单透明背景指南【技巧】  非常酷的网站设计制作软件,酷培ai教育官方网站?  在线ppt制作网站有哪些软件,如何把网页的内容做成ppt?  太平洋网站制作公司,网络用语太平洋是什么意思?  使用Dockerfile构建java web环境  Python并发异常传播_错误处理解析【教程】  怎么用AI帮你为初创公司进行市场定位分析?  Laravel如何使用Blade模板引擎?(完整语法和示例)  Java类加载基本过程详细介绍  Laravel如何构建RESTful API_Laravel标准化API接口开发指南  Laravel如何清理系统缓存命令_Laravel清除路由配置及视图缓存的方法【总结】  如何在阿里云虚拟服务器快速搭建网站?  如何在景安云服务器上绑定域名并配置虚拟主机?  Laravel怎么进行数据库事务处理_Laravel DB Facade事务操作确保数据一致性  青岛网站建设如何选择本地服务器?  MySQL查询结果复制到新表的方法(更新、插入)  如何在Windows环境下新建FTP站点并设置权限?