如何控制 RedirectIfAuthenticated 行为?

问题描述 投票:0回答:7

这是 Laravel 11 + Fortify + Sanctum。我使用 Laravel 作为我的 API 后端。前端是第一方 SPA。

我刚刚使用 Thunder 客户端 (XHR) 测试我的登录端点 (POST)。当登录调用成功一次时,对登录端点的任何后续调用都会发出到根 URL 的重定向,而不是返回 JSON 响应,告诉用户已通过身份验证。这意味着调用者将得到 405(方法不允许)作为最终响应,因为根 url 上没有 POST 端点。

过去,我们可以通过修改

RedirectIfAuthenticated
中间件并仅在这不是 XHR 时进行重定向来控制这种错误行为。在 Laravel 11 中,他们已将这些中间件移至框架本身中。我还听说他们已经解决了问题本身,因此无需再编辑中间件,但我仍然看到该错误。

我还尝试了 Laravel 11 的新辅助方法来覆盖这样的重定向行为(在

bootstrap/app.php
中):

$middleware->redirectUsersTo(function() {
    if(request()->wantsJson()) {
        return response()->json(['result' => 'success'], 200);
    } else {
        return '/home';
    }
});

但这会导致其他不相关的问题。我在这里错过了什么吗?

更新

我发现将以下内容添加到

RedirectIfAuthenticated
中间件的
handle
函数可以解决问题:

if ($request->expectsJson())
  return response()->json(['message' => 'authenticated.'], 200);

这个问题和这个修复似乎已经众所周知很多年了。然而,事实上,这个中间件现在是 Laravel 11 框架的一部分,并且位于

vendor
目录中,这意味着我必须手动将这一行添加到部署中,并注意它在更新期间不会被覆盖。不明白为什么 Laravel 在过去的几个主要版本中没有添加这个简单的检查。

php laravel laravel-sanctum laravel-fortify laravel-11
7个回答
4
投票
// In app\Providers\AppServiceProvider.php
// In the boot function paste the code snippet below and change the route accordingly
use Illuminate\Auth\Middleware\RedirectIfAuthenticated;
// Redirect Authenticated Users
    RedirectIfAuthenticated::redirectUsing(function () {
        return route('dashboard');
    });

2
投票

找到解决方案。您需要在

home
中有一条名为
dashboard
api.php
的路线。定义此路由后,对
login
的任何后续调用都会正确返回 JSON 数据(由
home
路由返回),并且不会发生重定向。

正如问题中提到的,只有当用户已经登录(并且设置了 cookie)时才会发生重定向问题。未经身份验证的用户过去常常在第一次

login
调用时获得正确的 JSON 响应。添加
/home
路线可解决此问题。

看起来这些名称是硬编码在 Laravel 11 的中间件中的。由于中间件现在是框架的一部分,因此您无法在用户态代码中更改它。请注意,早些时候我也尝试过用我的自定义实现来覆盖默认中间件,但无法使其工作。


2
投票

基于kris gjika的建议,您可以创建

app/Http/Middleware/RedirectIfAuthenticated.php
,扩展默认中间件,例如(https://onlinephp.io/c/ee199)。然后在 bootstrap/app.php 中使用它。

->withMiddleware(function (Middleware $middleware) {
        $middleware->statefulApi();
        $middleware->alias(['json_guest'=> RedirectIfAuthenticated::class]);
    })

有了这个,您可以在路由文件中将“guest”中间件替换为“json_guest”


1
投票

我也面临这个问题,从 Laravel 4 到 10,这从来都不是问题,因为我们习惯于根据需要修改

RedirectIfAuthenticated
类。

这个问题的解决方案有点棘手,但可以通过创建一个自定义中间件来完成,该中间件扩展主 RedirectIfAuthenticated 类并覆盖句柄函数。我想知道为什么 Laravel 团队没有在内部实现这一点,因为 sainttum 对基于不记名令牌的请求有一个后备检查。

解决方案

要让 Sanctum 发挥其功能,同时在发出 JSON 请求时修改 JSON 响应,请按以下方式完成:

第 1 步创建一个扩展供应商中间件的自定义中间件
// File: App/Http/Middleware/RedirectIfAuthenticated.php

use Illuminate\Http\JsonResponse;
use Illuminate\Auth\Middleware\RedirectIfAuthenticated as RedirectIfAuthenticatedMiddleware;

use Auth;

class RedirectIfAuthenticated extends RedirectIfAuthenticatedMiddleware
{

    public function handle(Request $request, Closure $next, string ...$guards): Response|JsonResponse
    {
        $guards = empty($guards) ? [null] : $guards;

        foreach ($guards as $guard) {
            if (Auth::guard($guard)->check()) {
                if ($request->expectsJson()) {
                    return response()->json([
                        'message' => 'Authenticated users cannot access this resource.'
                    ], 403); 
                }

                return redirect($this->redirectTo($request));
            }
        }

        return $next($request);
    }

}
第 2 步覆盖 app.php 中的访客别名
// File: bootstrap/app.php

    ->withMiddleware(function (Middleware $middleware) {
        $middleware->api(prepend: [
            \Illuminate\Session\Middleware\StartSession::class,
            \Laravel\Sanctum\Http\Middleware\EnsureFrontendRequestsAreStateful::class,
        ]);


        $middleware->alias([
            'verified' => \App\Http\Middleware\EnsureEmailIsVerified::class,
            'guest'    => \App\Http\Middleware\RedirectIfAuthenticated::class,
        ]);
    })

1
投票

您可以使用应用程序 bootstrap/app.php 的方法redirectGuestsTo 来修改此行为: https://laravel.com/docs/11.x/authentication#redirecting-unauthenticated-users

<?php

use Illuminate\Http\Request;

->withMiddleware(function (Middleware $middleware) {
    $middleware->redirectGuestsTo('/login');

    // Using a closure...
    $middleware->redirectGuestsTo(fn (Request $request) => route('login'));
})

0
投票

我无法直接回答对此线程的一些贡献,但以防万一,与更改

guest
别名类似,您可以在
$middleware->replace(...)
中使用
app.php

我尝试了所选答案中概述的方法,但没有成功。中间件将重定向到

/
而不是
/home
/dashboard

编辑:尝试登录新注册用户时仍然出现错误。


0
投票

例如,您必须希望在会话结束时重定向页面

  • 转到目录=> bootstrap > app.php

    ->withMiddleware(函数 (中间件 $middleware) {

          $middleware->redirectGuestsTo(fn () => route('login'));
    

    })

如果您有不止一名守卫

->withMiddleware(function (Middleware $middleware) {
        
        $middleware->redirectGuestsTo(function ($request) {

            if (!$request->expectsJson()) {

                if (in_array('auth:admin', $request->route()->middleware())) {

                    if (!auth('admin')->check()) {

                        return url('dashboard/admin/login');
                    }

                }//end if if admin auth

            }//end of if
            
        });
        
    })
© www.soinside.com 2019 - 2024. All rights reserved.