Authentication

Introduction

许多 Web 应用程序为其用户提供了一种通过应用程序进行身份验证和“登录”的方法。在 Web 应用程序中实现此功能可能是一项复杂且具有潜在风险的工作。出于这个原因,Laravel 努力为您提供快速、安全、轻松地实现身份验证所需的工具。

Laravel 的身份验证工具的核心是由“守卫”和“提供者”组成的。 Guards 定义如何为每个请求对用户进行身份验证。例如,Laravel 附带了一个session 使用会话存储和 cookie 维护状态的守卫。

提供商定义如何从您的持久存储中检索用户。 Laravel 支持使用检索用户Eloquent 和数据库查询生成器。但是,您可以根据应用程序的需要自由定义其他提供程序。

您的应用程序的身份验证配置文件位于config/auth.php.这个文件包含几个有据可查的选项,用于调整 Laravel 身份验证服务的行为。

Note
警卫和提供者不应与“角色”和“权限”混淆。要了解有关通过权限授权用户操作的更多信息,请参阅authorization 文档。

入门套件

想要快速入门?安装一个Laravel 应用程序入门套件 在一个新的 Laravel 应用程序中。迁移数据库后,将浏览器导航至/register 或分配给您的应用程序的任何其他 URL。初学者工具包将负责构建您的整个身份验证系统!

即使您选择不在最终的 Laravel 应用程序中使用入门工具包,安装Laravel 微风 初学者工具包是学习如何在实际的 Laravel 项目中实现所有 Laravel 身份验证功能的绝好机会。 由于 Laravel Breeze 为您创建了身份验证控制器、路由和视图,您可以检查这些文件中的代码以了解如何实现 Laravel 的身份验证功能。

数据库注意事项

默认情况下,Laravel 包括一个App\Models\User 口才模型 在你的app/Models 目录。该模型可以与默认的 Eloquent 身份验证驱动程序一起使用。如果你的应用程序没有使用 Eloquent,你可以使用database 使用 Laravel 查询生成器的身份验证提供程序。

在为App\Models\User 型号,请确保密码栏的长度至少为 60 个字符。当然,users 新的 Laravel 应用程序中包含的表迁移已经创建了一个超过此长度的列。

此外,您应该验证您的users (或等效)表包含一个可为空的字符串remember_token 100 个字符的列。此列将用于为登录您的应用程序时选择“记住我”选项的用户存储令牌。再次,默认users 新的 Laravel 应用程序中包含的表迁移已经包含此列。

生态系统概览

Laravel 提供了几个与身份验证相关的包。在继续之前,我们将回顾 Laravel 中的通用身份验证生态系统并讨论每个包的预期用途。

首先,考虑身份验证的工作原理。使用网络浏览器时,用户将通过登录表单提供他们的用户名和密码。如果这些凭据正确,应用程序将在用户的session.发给浏览器的 cookie 包含会话 ID,以便对应用程序的后续请求可以将用户与正确的会话相关联。收到session cookie后,应用程序会根据session ID检索session数据,注意session中已经存储了认证信息,会认为用户“已通过认证”。

当远程服务需要通过身份验证才能访问 API 时,cookie 通常不会用于身份验证,因为没有 Web 浏览器。相反,远程服务会在每次请求时向 API 发送一个 API 令牌。应用程序可以根据有效 API 令牌表验证传入令牌,并“验证”请求是由与该 API 令牌相关联的用户执行的。

Laravel 内置的浏览器认证服务

Laravel 包含内置的身份验证和会话服务,通常可以通过AuthSession 门面。这些功能为从 Web 浏览器发起的请求提供基于 cookie 的身份验证。它们提供的方法允许您验证用户的凭据并对用户进行身份验证。此外,这些服务会自动将正确的身份验证数据存储在用户的会话中,并发布用户的会话 cookie。本文档中包含对如何使用这些服务的讨论。

应用入门套件

如本文档中所述,您可以手动与这些身份验证服务交互以构建应用程序自己的身份验证层。但是,为了帮助您更快地入门,我们发布了免费套餐 为整个身份验证层提供强大的现代脚手架。这些包是Laravel 微风,Laravel 喷射流, 和Laravel 强化.

Laravel 微风 是所有 Laravel 身份验证功能的简单、最小的实现,包括登录、注册、密码重置、电子邮件验证和密码确认。 Laravel Breeze 的视图层由简单的刀片模板 风格与顺风 CSS.要开始,请查看 Laravel 的文档应用入门套件.

Laravel 强化 是 Laravel 的无头身份验证后端,它实现了本文档中的许多功能,包括基于 cookie 的身份验证以及其他功能,例如双因素身份验证和电子邮件验证。 Fortify 为 Laravel Jetstream 提供身份验证后端,也可以独立使用Laravel 圣殿 为需要使用 Laravel 进行身份验证的 SPA 提供身份验证。

Laravel 喷射流 是一个强大的应用程序入门工具包,它使用由顺风 CSS,Livewire, 和/或Inertia. Laravel Jetstream 包括对双因素身份验证、团队支持、浏览器会话管理、配置文件管理和内置集成的可选支持Laravel 圣殿 提供 API 令牌身份验证。 Laravel 的 API 身份验证产品将在下面讨论。

Laravel 的 API 认证服务

Laravel 提供了两个可选包来帮助您管理 API 令牌和验证使用 API 令牌发出的请求:PassportSanctum.请注意,这些库和 Laravel 内置的基于 cookie 的身份验证库并不相互排斥。这些库主要关注 API 令牌身份验证,而内置身份验证服务则关注基于 cookie 的浏览器身份验证。许多应用程序将同时使用 Laravel 内置的基于 cookie 的身份验证服务和 Laravel 的 API 身份验证包之一。

Passport

Passport 是一个 OAuth2 身份验证提供程序,提供各种 OAuth2“授权类型”,允许您颁发各种类型的令牌。总的来说,这是一个强大而复杂的 API 身份验证包。但是,大多数应用程序不需要 OAuth2 规范提供的复杂功能,这可能会让用户和开发人员感到困惑。此外,开发人员一直对如何使用 Passport 等 OAuth2 身份验证提供程序对 SPA 应用程序或移动应用程序进行身份验证感到困惑。

Sanctum

为了应对 OAuth2 的复杂性和开发人员的困惑,我们着手构建一个更简单、更精简的身份验证包,可以处理来自 Web 浏览器的第一方 Web 请求和通过令牌的 API 请求。这个目标是随着发布而实现的Laravel 圣殿,它应该被认为是应用程序的首选和推荐的身份验证包,这些应用程序将提供除 API 之外的第一方 Web UI,或者将由与后端 Laravel 应用程序分开存在的单页应用程序(SPA)提供支持,或提供移动客户端的应用程序。

Laravel Sanctum 是一个混合的 web / API 身份验证包,可以管理你的应用程序的整个身份验证过程。这是可能的,因为当基于 Sanctum 的应用程序收到请求时,Sanctum 将首先确定该请求是否包含引用经过身份验证的会话的会话 cookie。 Sanctum 通过调用我们之前讨论过的 Laravel 的内置身份验证服务来实现这一点。如果请求未通过会话 cookie 进行身份验证,Sanctum 将检查 API 令牌的请求。如果存在 API 令牌,Sanctum 将使用该令牌对请求进行身份验证。要了解有关此过程的更多信息,请咨询 Sanctum 的“怎么运行的” 文档。

Laravel Sanctum 是我们选择包含在Laravel 喷射流 应用程序入门工具包,因为我们相信它最适合大多数 Web 应用程序的身份验证需求。

总结和选择你的堆栈

总之,如果您的应用程序将使用浏览器访问,并且您正在构建一个单体 Laravel 应用程序,那么您的应用程序将使用 Laravel 的内置身份验证服务。

接下来,如果您的应用程序提供了一个将由第三方使用的 API,您将在两者之间进行选择Passport 或者Sanctum 为您的应用程序提供 API 令牌身份验证。通常,应尽可能首选 Sanctum,因为它是 API 身份验证、SPA 身份验证和移动身份验证的简单、完整的解决方案,包括对“范围”或“能力”的支持。

如果您正在构建将由 Laravel 后端提供支持的单页应用程序 (SPA),您应该使用Laravel 圣殿.使用 Sanctum 时,您需要手动实现您自己的后端身份验证路由 或利用Laravel 强化 作为无外设身份验证后端服务,为注册、密码重置、电子邮件验证等功能提供路由和控制器。

当您的应用程序绝对需要 OAuth2 规范提供的所有功能时,可以选择 Passport。

而且,如果您想快速入门,我们很乐意向您推荐Laravel 微风 作为启动新 Laravel 应用程序的快速方法,该应用程序已经使用了我们首选的 Laravel 内置身份验证服务和 Laravel Sanctum 身份验证堆栈。

身份验证快速入门

Warning
文档的这一部分讨论了通过Laravel 应用程序入门套件,其中包括可帮助您快速入门的 UI 脚手架。如果您想直接与 Laravel 的身份验证系统集成,请查看文档手动验证用户.

安装入门套件

首先,你应该安装 Laravel 应用程序入门工具包.我们当前的入门套件 Laravel Breeze 和 Laravel Jetstream 提供了设计精美的起点,可将身份验证整合到您全新的 Laravel 应用程序中。

Laravel Breeze 是 Laravel 所有身份验证功能的最小化、简单实现,包括登录、注册、密码重置、电子邮件验证和密码确认。 Laravel Breeze 的视图层由简单的刀片模板 风格与顺风 CSS.微风还提供了一个Inertia 使用 Vue 或 React 的基于脚手架选项。

Laravel 喷射流 是一个更健壮的应用程序入门工具包,包括对构建您的应用程序的支持Livewire 或者惯性和 Vue.此外,Jetstream 还提供对双因素身份验证、团队、配置文件管理、浏览器会话管理、API 支持的可选支持Laravel 圣殿、帐户删除等。

检索经过身份验证的用户

安装身份验证入门工具包并允许用户注册并使用您的应用程序进行身份验证后,您将经常需要与当前经过身份验证的用户进行交互。在处理传入请求时,您可以通过访问经过身份验证的用户Auth 门面的user 方法:

use Illuminate\Support\Facades\Auth;

// Retrieve the currently authenticated user...
$user = Auth::user();

// Retrieve the currently authenticated user's ID...
$id = Auth::id();

或者,一旦用户通过身份验证,您可以通过Illuminate\Http\Request 实例。请记住,类型提示类将自动注入到您的控制器方法中。通过类型提示Illuminate\Http\Request 对象,您可以通过请求的应用程序中的任何控制器方法方便地访问经过身份验证的用户user 方法:

<?php

namespace App\Http\Controllers;

use Illuminate\Http\RedirectResponse;
use Illuminate\Http\Request;

class FlightController extends Controller
{
    /**
     * Update the flight information for an existing flight.
     */
    public function update(Request $request): RedirectResponse
    {
        $user = $request->user();

        // ...

        return redirect('/flights');
    }
}

确定当前用户是否已通过身份验证

要确定发出传入 HTTP 请求的用户是否经过身份验证,您可以使用check 上的方法Auth 正面。这个方法会返回true 如果用户通过身份验证:

use Illuminate\Support\Facades\Auth;

if (Auth::check()) {
    // The user is logged in...
}

Note
即使可以使用check 方法,在允许用户访问某些路由/控制器之前,您通常会使用中间件来验证用户是否已通过身份验证。要了解更多信息,请查看文档保护路线.

保护路线

路由中间件 可用于仅允许经过身份验证的用户访问给定路由。 Laravel 附带一个auth 中间件,它引用了Illuminate\Auth\Middleware\Authenticate 班级。由于这个中间件已经在你的应用程序的 HTTP 内核中注册,你需要做的就是将中间件附加到路由定义中:

Route::get('/flights', function () {
    // Only authenticated users may access this route...
})->middleware('auth');

重定向未经身份验证的用户

当。。。的时候auth 中间件检测到未经身份验证的用户,它将把用户重定向到login 命名路线.您可以通过更新redirectTo 在你的应用程序中运行app/Http/Middleware/Authenticate.php 文件:

use Illuminate\Http\Request;

/**
 * Get the path the user should be redirected to.
 */
protected function redirectTo(Request $request): string
{
    return route('login');
}

指定守卫

当附上auth 中间件到路由,您还可以指定应该使用哪个“守卫”来验证用户。指定的守卫应对应于guards 你的数组auth.php 配置文件:

Route::get('/flights', function () {
    // Only authenticated users may access this route...
})->middleware('auth:admin');

登录节流

如果您使用的是 Laravel Breeze 或 Laravel Jetstream入门套件,速率限制将自动应用于登录尝试。默认情况下,如果用户在多次尝试后未能提供正确的凭据,他们将在一分钟内无法登录。限制对于用户的用户名/电子邮件地址及其 IP 地址是唯一的。

Note
如果您想对应用程序中的其他路由进行速率限制,请查看速率限制文档.

手动验证用户

您不需要使用 Laravel 中包含的身份验证脚手架应用入门套件.如果你选择不使用这个脚手架,你将需要直接使用 Laravel 身份验证类来管理用户身份验证。别担心,小菜一碟!

我们将通过以下方式访问 Laravel 的身份验证服务Auth facade,所以我们需要确保导入Auth 门面在班级的顶部。接下来,让我们看看attempt 方法。这attempt 方法通常用于处理来自应用程序“登录”表单的身份验证尝试。如果身份验证成功,则应重新生成用户的session 阻止会话固定:

<?php

namespace App\Http\Controllers;

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

class LoginController extends Controller
{
    /**
     * Handle an authentication attempt.
     */
    public function authenticate(Request $request): RedirectResponse
    {
        $credentials = $request->validate([
            'email' => ['required', 'email'],
            'password' => ['required'],
        ]);

        if (Auth::attempt($credentials)) {
            $request->session()->regenerate();

            return redirect()->intended('dashboard');
        }

        return back()->withErrors([
            'email' => 'The provided credentials do not match our records.',
        ])->onlyInput('email');
    }
}

attempt 方法接受一个键/值对数组作为它的第一个参数。数组中的值将用于在数据库表中查找用户。因此,在上面的示例中,用户将通过email柱子。如果找到用户,则将存储在数据库中的散列密码与password 通过数组传递给方法的值。你不应该散列传入的请求password 值,因为框架会在将该值与数据库中的哈希密码进行比较之前自动对其进行哈希处理。如果两个散列密码匹配,将为用户启动经过身份验证的会话。

请记住,Laravel 的身份验证服务将根据您的身份验证守卫的“提供者”配置从您的数据库中检索用户。在默认情况下config/auth.php 配置文件中,指定了 Eloquent 用户提供程序,并指示使用App\Models\User 检索用户时的模型。您可以根据应用程序的需要在配置文件中更改这些值。

attempt 方法将返回true 如果认证成功。否则,false 将被退回。

intended Laravel 的重定向器提供的方法会将用户重定向到他们在被身份验证中间件拦截之前尝试访问的 URL。如果预期目的地不可用,可以为该方法提供回退 URI。

指定附加条件

如果您愿意,除了用户的电子邮件和密码之外,您还可以向身份验证查询添加额外的查询条件。为此,我们可以简单地将查询条件添加到传递给attempt 方法。例如,我们可以验证用户是否被标记为“活跃”:

if (Auth::attempt(['email' => $email, 'password' => $password, 'active' => 1])) {
    // Authentication was successful...
}

对于复杂的查询条件,您可以在凭证数组中提供闭包。此闭包将与查询实例一起调用,允许您根据应用程序的需要自定义查询:

use Illuminate\Database\Eloquent\Builder;

if (Auth::attempt([
    'email' => $email, 
    'password' => $password, 
    fn (Builder $query) => $query->has('activeSubscription'),
])) {
    // Authentication was successful...
}

Warning
在这些例子中,email 不是必需的选项,它仅用作示例。您应该使用与数据库表中的“用户名”相对应的任何列名。

attemptWhen 方法接收闭包作为其第二个参数,可用于在实际验证用户之前对潜在用户执行更广泛的检查。闭包接收潜在用户并应返回true 或者false 指示用户是否可以通过身份验证:

if (Auth::attemptWhen([
    'email' => $email,
    'password' => $password,
], function (User $user) {
    return $user->isNotBanned();
})) {
    // Authentication was successful...
}

访问特定的守卫实例

通过Auth 门面的guard 方法,您可以指定在对用户进行身份验证时要使用哪个守卫实例。这允许您使用完全独立的可验证模型或用户表来管理应用程序不同部分的验证。

守卫名字传递给guard 方法应该对应于你配置的守卫之一auth.php 配置文件:

if (Auth::guard('admin')->attempt($credentials)) {
    // ...
}

记住用户

许多 Web 应用程序在其登录表单上提供“记住我”复选框。如果您想在您的应用程序中提供“记住我”功能,您可以将布尔值作为第二个参数传递给attempt 方法。

当这个值是true,Laravel 将无限期地保持用户身份验证或直到他们手动注销。你的users 表格必须包含字符串remember_token 列,它将用于存储“记住我”令牌。这users 新的 Laravel 应用程序中包含的表迁移已经包含此列:

use Illuminate\Support\Facades\Auth;

if (Auth::attempt(['email' => $email, 'password' => $password], $remember)) {
    // The user is being remembered...
}

如果您的应用程序提供“记住我”功能,您可以使用viaRemember 确定当前已验证用户是否使用“记住我”cookie 进行验证的方法:

use Illuminate\Support\Facades\Auth;

if (Auth::viaRemember()) {
    // ...
}

其他身份验证方法

验证用户实例

如果您需要将现有用户实例设置为当前经过身份验证的用户,您可以将用户实例传递给Auth 门面的login 方法。给定的用户实例必须是Illuminate\Contracts\Auth\Authenticatable contract.这App\Models\User Laravel 包含的模型已经实现了这个接口。当您已经有一个有效的用户实例时,这种身份验证方法很有用,例如在用户注册您的应用程序之后:

use Illuminate\Support\Facades\Auth;

Auth::login($user);

您可以将布尔值作为第二个参数传递给login 方法。此值指示经过身份验证的会话是否需要“记住我”功能。请记住,这意味着会话将无限期地进行身份验证,或者直到用户手动注销应用程序为止:

Auth::login($user, $remember = true);

如果需要,您可以在调用login 方法:

Auth::guard('admin')->login($user);

通过 ID 验证用户

要使用数据库记录的主键对用户进行身份验证,您可以使用loginUsingId 方法。此方法接受您要验证的用户的主键:

Auth::loginUsingId(1);

您可以将布尔值作为第二个参数传递给loginUsingId 方法。此值指示经过身份验证的会话是否需要“记住我”功能。请记住,这意味着会话将无限期地进行身份验证,或者直到用户手动注销应用程序为止:

Auth::loginUsingId(1, $remember = true);

验证用户一次

您可以使用once 方法来对单个请求的应用程序的用户进行身份验证。调用此方法时不会使用会话或 cookie:

if (Auth::once($credentials)) {
    // ...
}

HTTP 基本认证

HTTP 基本认证 提供了一种无需设置专用“登录”页面即可对应用程序用户进行身份验证的快速方法。首先,附上auth.basic middleware 到一条路线。这auth.basic 中间件包含在 Laravel 框架中,所以你不需要定义它:

Route::get('/profile', function () {
    // Only authenticated users may access this route...
})->middleware('auth.basic');

将中间件附加到路由后,当您在浏览器中访问路由时,系统会自动提示您输入凭据。默认情况下,auth.basic 中间件将承担email 你的专栏users 数据库表是用户的“用户名”。

关于 FastCGI 的注释

如果您使用 PHP FastCGI 和 Apache 来为您的 Laravel 应用程序提供服务,则 HTTP Basic 身份验证可能无法正常工作。要纠正这些问题,可以将以下行添加到您的应用程序的.htaccess 文件:

RewriteCond %{HTTP:Authorization} ^(.+)$
RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]

无状态 HTTP 基本身份验证

您也可以在会话中不设置用户标识符 cookie 的情况下使用 HTTP 基本身份验证。如果您选择使用 HTTP 身份验证来验证对应用程序 API 的请求,这将非常有用。为了做到这一点,定义一个中间件 那个叫onceBasic 方法。如果没有响应返回onceBasic 方法,可以将请求进一步传递到应用程序中:

<?php

namespace App\Http\Middleware;

use Closure;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;
use Symfony\Component\HttpFoundation\Response;

class AuthenticateOnceWithBasicAuth
{
    /**
     * Handle an incoming request.
     *
     * @param  \Closure(\Illuminate\Http\Request): (\Symfony\Component\HttpFoundation\Response)  $next
     */
    public function handle(Request $request, Closure $next): Response
    {
        return Auth::onceBasic() ?: $next($request);
    }

}

接下来,将中间件附加到路由:

Route::get('/api/user', function () {
    // Only authenticated users may access this route...
})->middleware(AuthenticateOnceWithBasicAuth::class);

注销

要手动将用户从您的应用程序中注销,您可以使用logout 提供的方法Auth 正面。这将从用户的会话中删除身份验证信息,以便不对后续请求进行身份验证。

除了调用logout 方法,建议您使用户的会话无效并重新生成他们的CSRF令牌.注销用户后,您通常会将用户重定向到应用程序的根目录:

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

/**
 * Log the user out of the application.
 */
public function logout(Request $request): RedirectResponse
{
    Auth::logout();

    $request->session()->invalidate();

    $request->session()->regenerateToken();

    return redirect('/');
}

在其他设备上使会话无效

Laravel 还提供了一种机制,可以在不使用户当前设备​​上的会话无效的情况下,使在其他设备上处于活动状态的用户会话无效和“注销”。当用户更改或更新他们的密码并且您希望在保持当前设备经过身份验证的同时使其他设备上的会话无效时,通常会使用此功能。

在开始之前,您应该确保Illuminate\Session\Middleware\AuthenticateSession 中间件包含在应该接收会话身份验证的路由中。通常,您应该将此中间件放在路由组定义中,以便它可以应用于您应用程序的大部分路由。默认情况下,AuthenticateSession 中间件可以使用auth.session 应用程序的 HTTP 内核中定义的路由中间件别名:

Route::middleware(['auth', 'auth.session'])->group(function () {
    Route::get('/', function () {
        // ...
    });
});

然后,您可以使用logoutOtherDevices 提供的方法Auth 正面。此方法要求用户确认其当前密码,您的应用程序应通过输入表单接受该密码:

use Illuminate\Support\Facades\Auth;

Auth::logoutOtherDevices($currentPassword);

当。。。的时候logoutOtherDevices 方法被调用时,用户的其他会话将完全失效,这意味着他们将“注销”之前验证过的所有守卫。

确认密码

在构建您的应用程序时,您可能偶尔会要求用户在执行操作之前或在将用户重定向到应用程序的敏感区域之前确认其密码。 Laravel 包含内置的中间件,使这个过程变得轻而易举。实现此功能将需要您定义两条路线:一条路线显示要求用户确认其密码的视图,另一条路线确认密码有效并将用户重定向到他们的预期目的地。

Note
以下文档讨论了如何直接与 Laravel 的密码确认功能集成;但是,如果您想更快地开始,Laravel 应用程序入门套件 包括对此功能的支持!

Configuration

确认密码后,三个小时内不会要求用户再次确认密码。但是,您可以通过更改password_timeout 应用程序中的配置值config/auth.php 配置文件。

Routing

密码确认表

首先,我们将定义一个路由来显示一个请求用户确认密码的视图:

Route::get('/confirm-password', function () {
    return view('auth.confirm-password');
})->middleware('auth')->name('password.confirm');

如您所料,此路由返回的视图应该有一个包含password 场地。此外,请随意在视图中包含说明用户正在进入应用程序受保护区域并且必须确认其密码的文本。

确认密码

接下来,我们将定义一个路由来处理来自“确认密码”视图的表单请求。此路由将负责验证密码并将用户重定向到他们的预期目的地:

use Illuminate\Http\Request;
use Illuminate\Support\Facades\Hash;
use Illuminate\Support\Facades\Redirect;

Route::post('/confirm-password', function (Request $request) {
    if (! Hash::check($request->password, $request->user()->password)) {
        return back()->withErrors([
            'password' => ['The provided password does not match our records.']
        ]);
    }

    $request->session()->passwordConfirmed();

    return redirect()->intended();
})->middleware(['auth', 'throttle:6,1']);

在继续之前,让我们更详细地研究这条路线。首先,请求的password 字段被确定为实际匹配经过身份验证的用户的密码。如果密码有效,我们需要通知 Laravel 的会话用户已经确认了他们的密码。这passwordConfirmed 方法将在用户的会话中设置一个时间戳,Laravel 可以使用它来确定用户最后一次确认密码的时间。最后,我们可以将用户重定向到他们想要的目的地。

保护路线

您应该确保为执行需要最近密码确认的操作的任何路由分配password.confirm 中间件。这个中间件包含在 Laravel 的默认安装中,并且会自动将用户的预期目的地存储在会话中,以便用户在确认密码后可以被重定向到该位置。在会话中存储用户的预期目的地后,中间件会将用户重定向到password.confirm 命名路线:

Route::get('/settings', function () {
    // ...
})->middleware(['password.confirm']);

Route::post('/settings', function () {
    // ...
})->middleware(['password.confirm']);

添加自定义守卫

您可以使用extend 上的方法Auth 正面。你应该打电话给extend 一个内的方法服务提供者.由于 Laravel 已经附带了一个AuthServiceProvider,我们可以将代码放在该提供程序中:

<?php

namespace App\Providers;

use App\Services\Auth\JwtGuard;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * Register any application authentication / authorization services.
     */
    public function boot(): void
    {
        Auth::extend('jwt', function (Application $app, string $name, array $config) {
            // Return an instance of Illuminate\Contracts\Auth\Guard...

            return new JwtGuard(Auth::createUserProvider($config['provider']));
        });
    }
}

正如您在上面的示例中看到的,回调传递给extend 方法应该返回一个实现Illuminate\Contracts\Auth\Guard.这个接口包含一些你需要实现的方法来定义一个自定义守卫。定义自定义守卫后,您可以在guards 你的配置auth.php 配置文件:

'guards' => [
    'api' => [
        'driver' => 'jwt',
        'provider' => 'users',
    ],
],

关闭请求守卫

实现自定义的、基于 HTTP 请求的身份验证系统的最简单方法是使用Auth::viaRequest 方法。此方法允许您使用单个闭包快速定义身份验证过程。

要开始,请致电Auth::viaRequest 内的方法boot 你的方法AuthServiceProvider.这viaRequest 方法接受身份验证驱动程序名称作为其第一个参数。此名称可以是描述您的自定义守卫的任何字符串。传递给该方法的第二个参数应该是一个闭包,它接收传入的 HTTP 请求并返回一个用户实例,或者,如果身份验证失败,null:

use App\Models\User;
use Illuminate\Http\Request;
use Illuminate\Support\Facades\Auth;

/**
 * Register any application authentication / authorization services.
 */
public function boot(): void
{
    Auth::viaRequest('custom-token', function (Request $request) {
        return User::where('token', $request->token)->first();
    });
}

定义自定义身份验证驱动程序后,您可以将其配置为guards 你的配置auth.php 配置文件:

'guards' => [
    'api' => [
        'driver' => 'custom-token',
    ],
],

最后,您可以在将身份验证中间件分配给路由时引用守卫:

Route::middleware('auth:api')->group(function () {
    // ...
}

添加自定义用户提供商

如果您不使用传统的关系数据库来存储您的用户,您将需要使用您自己的身份验证用户提供程序来扩展 Laravel。我们将使用provider 上的方法Auth facade 来定义自定义用户提供者。用户提供者解析器应该返回一个实现Illuminate\Contracts\Auth\UserProvider:

<?php

namespace App\Providers;

use App\Extensions\MongoUserProvider;
use Illuminate\Contracts\Foundation\Application;
use Illuminate\Foundation\Support\Providers\AuthServiceProvider as ServiceProvider;
use Illuminate\Support\Facades\Auth;

class AuthServiceProvider extends ServiceProvider
{
    /**
     * Register any application authentication / authorization services.
     */
    public function boot(): void
    {
        Auth::provider('mongo', function (Application $app, array $config) {
            // Return an instance of Illuminate\Contracts\Auth\UserProvider...

            return new MongoUserProvider($app->make('mongo.connection'));
        });
    }
}

在您使用provider 方法,您可以在您的auth.php配置文件。首先,定义一个provider 使用您的新驱动程序:

'providers' => [
    'users' => [
        'driver' => 'mongo',
    ],
],

最后,您可以在您的guards 配置:

'guards' => [
    'web' => [
        'driver' => 'session',
        'provider' => 'users',
    ],
],

用户提供商合同

Illuminate\Contracts\Auth\UserProvider 实现负责获取Illuminate\Contracts\Auth\Authenticatable 从持久存储系统(如 MySQL、MongoDB 等)中实现。这两个接口允许 Laravel 身份验证机制继续运行,无论用户数据如何存储或使用什么类型的类来表示经过身份验证的用户:

让我们来看看Illuminate\Contracts\Auth\UserProvider 合同:

<?php

namespace Illuminate\Contracts\Auth;

interface UserProvider
{
    public function retrieveById($identifier);
    public function retrieveByToken($identifier, $token);
    public function updateRememberToken(Authenticatable $user, $token);
    public function retrieveByCredentials(array $credentials);
    public function validateCredentials(Authenticatable $user, array $credentials);
}

retrieveById 函数通常接收代表用户的键,例如来自 MySQL 数据库的自动递增 ID。这Authenticatable 该方法应检索并返回与 ID 匹配的实现。

retrieveByToken 函数通过用户的唯一性检索用户$identifier 和“记住我”$token,通常存储在数据库列中,例如remember_token.与之前的方法一样,Authenticatable 此方法应返回具有匹配标记值的实现。

updateRememberToken 方法更新$user 实例的remember_token 与新的$token.在成功的“记住我”身份验证尝试或用户注销时,会将新令牌分配给用户。

retrieveByCredentials 方法接收传递给Auth::attempt 尝试对应用程序进行身份验证时的方法。然后,该方法应该“查询”底层持久存储以查找与这些凭据匹配的用户。通常,此方法将运行一个带有“where”条件的查询,以搜索“用户名”与值匹配的用户记录$credentials['username'].该方法应该返回一个实现Authenticatable.此方法不应尝试进行任何密码验证或身份验证。

validateCredentials 方法应该比较给定的$user$credentials 对用户进行身份验证。例如,此方法通常会使用Hash::check 比较值的方法$user->getAuthPassword() 的价值$credentials['password'].这个方法应该返回true 或者false 指示密码是否有效。

可验证的合同

现在我们已经探索了每个方法UserProvider,让我们来看看Authenticatable 合同。请记住,用户提供者应该从retrieveById,retrieveByToken, 和retrieveByCredentials 方法:

<?php

namespace Illuminate\Contracts\Auth;

interface Authenticatable
{
    public function getAuthIdentifierName();
    public function getAuthIdentifier();
    public function getAuthPassword();
    public function getRememberToken();
    public function setRememberToken($value);
    public function getRememberTokenName();
}

这个界面很简单。这getAuthIdentifierName 方法应该返回用户的“主键”字段的名称和getAuthIdentifier 方法应该返回用户的“主键”。当使用 MySQL 后端时,这可能是分配给用户记录的自动递增主键。这getAuthPassword 方法应返回用户的散列密码。

该接口允许身份验证系统与任何“用户”类一起工作,而不管您使用的是什么 ORM 或存储抽象层。默认情况下,Laravel 包括一个App\Models\User 中的类app/Models 实现此接口的目录。

Events

Laravel 派发各种events 在认证过程中。您可以在您的EventServiceProvider:

/**
 * The event listener mappings for the application.
 *
 * @var array
 */
protected $listen = [
    'Illuminate\Auth\Events\Registered' => [
        'App\Listeners\LogRegisteredUser',
    ],

    'Illuminate\Auth\Events\Attempting' => [
        'App\Listeners\LogAuthenticationAttempt',
    ],

    'Illuminate\Auth\Events\Authenticated' => [
        'App\Listeners\LogAuthenticated',
    ],

    'Illuminate\Auth\Events\Login' => [
        'App\Listeners\LogSuccessfulLogin',
    ],

    'Illuminate\Auth\Events\Failed' => [
        'App\Listeners\LogFailedLogin',
    ],

    'Illuminate\Auth\Events\Validated' => [
        'App\Listeners\LogValidated',
    ],

    'Illuminate\Auth\Events\Verified' => [
        'App\Listeners\LogVerified',
    ],

    'Illuminate\Auth\Events\Logout' => [
        'App\Listeners\LogSuccessfulLogout',
    ],

    'Illuminate\Auth\Events\CurrentDeviceLogout' => [
        'App\Listeners\LogCurrentDeviceLogout',
    ],

    'Illuminate\Auth\Events\OtherDeviceLogout' => [
        'App\Listeners\LogOtherDeviceLogout',
    ],

    'Illuminate\Auth\Events\Lockout' => [
        'App\Listeners\LogLockout',
    ],

    'Illuminate\Auth\Events\PasswordReset' => [
        'App\Listeners\LogPasswordReset',
    ],
];
豫ICP备18041297号-2