如何在 Jetstream 或 Fortify 中覆盖登录重定向
发布于 作者 Jason Beggs
最近,我在使用 Laravel Jetstream 的项目中遇到了一个场景,我需要根据用户的类型在登录后将用户重定向到不同的路由。假设您有普通用户和管理员,管理员有一个只有他们才能看到的特殊仪表盘。我通常更喜欢在管理员登录后将他们重定向到他们的特殊仪表盘。
使用 Laravel Jetstream 或 Fortify,并不立即清楚如何做到这一点,尤其是在使用双重身份验证时。
Jetstream 和 Fortify 中的身份验证工作原理
Jetstream 在后台使用 Laravel Fortify,因此对于运行 Fortify 本身的应用程序和运行 Jetstream 的项目,该过程完全相同。
Fortify 使用操作管道将每个请求通过一系列类,这些类负责执行单个任务,例如尝试验证用户或在用户设置了双重身份验证时重定向他们。
如何覆盖重定向步骤
如果需要,Fortify 允许您完全自定义这些管道,但有一种更简单的方法来覆盖重定向步骤。
身份验证管道中的最后一步从服务容器中获取 Laravel\Fortify\Contracts\LoginResponse
类并返回它。这意味着我们可以用我们自己的自定义 LoginResponse
类覆盖 LoginResponse
类,并在那里执行自定义重定向。
默认的 LoginResponse
类如下所示
<?php namespace Laravel\Fortify\Http\Responses; use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract; class LoginResponse implements LoginResponseContract{ /** * Create an HTTP response that represents the object. * * @param \Illuminate\Http\Request $request * @return \Symfony\Component\HttpFoundation\Response */ public function toResponse($request) { return $request->wantsJson() ? response()->json(['two_factor' => false]) : redirect()->intended(config('fortify.home')); }}
由于 Fortify 使用执行单个任务的操作,因此 LoginResponse
步骤非常简洁明了。
要自定义重定向,首先让我们在 app/Http/Responses
目录中添加我们自己的自定义 LoginResponse
类。然后,我们可以自定义 toResponse
方法,根据用户的类型将用户重定向到不同的路由。
<?php namespace App\Http\Responses; use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract; class LoginResponse implements LoginResponseContract{ /** * @param $request * @return mixed */ public function toResponse($request) { $home = auth()->user()->is_admin ? '/admin' : '/dashboard'; return redirect()->intended($home); }}
然后,在 FortifyServiceProvider
中,我们需要绑定我们自己的自定义 LoginResponse
类,以便覆盖 Fortify 提供的默认类。
<?php namespace App\Providers; // ...use App\Http\Responses\LoginResponse;use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract; class FortifyServiceProvider extends ServiceProvider{ /** * Bootstrap any application services. * * @return void */ public function boot() { // ... $this->app->singleton(LoginResponseContract::class, LoginResponse::class); }}
双重身份验证
这几乎完美地满足了我的需求。但是,还缺少一个部分 - 双重身份验证。如果用户启用了双重身份验证并登录,Fortify 将返回不同的响应类。幸运的是,双重身份验证类也绑定到服务容器。这次,我们需要在容器中覆盖 Laravel\Fortify\Http\Responses\TwoFactorLoginResponse
类。在 FortifyServiceProvider
中添加几行代码应该可以解决问题。
<?php namespace App\Providers; // ...use App\Http\Responses\LoginResponse;use Laravel\Fortify\Contracts\LoginResponse as LoginResponseContract;use Laravel\Fortify\Contracts\TwoFactorLoginResponse as TwoFactorLoginResponseContract; class FortifyServiceProvider extends ServiceProvider{ /** * Bootstrap any application services. * * @return void */ public function boot() { // ... $this->app->singleton(LoginResponseContract::class, LoginResponse::class); $this->app->singleton(TwoFactorLoginResponseContract::class, LoginResponse::class); }}
注意:我使用相同的自定义
LoginResponse
类覆盖TwoFactorLoginResponse
类,因为功能应该完全相同。
覆盖其他 Jetstream 和 Fortify 功能
Jetstream 和 Fortify 中的其他功能可以通过非常相似的方式进行自定义。如果您深入研究包中包含的 FortifyServiceProvider
(不是特定于您的项目的那个)并向下滚动到 registerResponseBindings
方法,您应该看到类似于以下内容
<?php namespace Laravel\Fortify; // ... class FortifyServiceProvider extends ServiceProvider{ // ... /** * Register the response bindings. * * @return void */ protected function registerResponseBindings() { $this->app->singleton(FailedPasswordConfirmationResponseContract::class, FailedPasswordConfirmationResponse::class); $this->app->singleton(FailedPasswordResetLinkRequestResponseContract::class, FailedPasswordResetLinkRequestResponse::class); $this->app->singleton(FailedPasswordResetResponseContract::class, FailedPasswordResetResponse::class); $this->app->singleton(FailedTwoFactorLoginResponseContract::class, FailedTwoFactorLoginResponse::class); $this->app->singleton(LockoutResponseContract::class, LockoutResponse::class); $this->app->singleton(LoginResponseContract::class, LoginResponse::class); $this->app->singleton(TwoFactorLoginResponseContract::class, TwoFactorLoginResponse::class); $this->app->singleton(LogoutResponseContract::class, LogoutResponse::class); $this->app->singleton(PasswordConfirmedResponseContract::class, PasswordConfirmedResponse::class); $this->app->singleton(PasswordResetResponseContract::class, PasswordResetResponse::class); $this->app->singleton(RegisterResponseContract::class, RegisterResponse::class); $this->app->singleton(SuccessfulPasswordResetLinkRequestResponseContract::class, SuccessfulPasswordResetLinkRequestResponse::class); } // ...}
这意味着如果需要,您的项目中可以覆盖所有这些响应类!
TALL 技术栈(Tailwind CSS、Alpine.js、Laravel 和 Livewire)顾问以及 designtotailwind.com 的所有者。