Это Laravel 11 + Fortify + Sanctum. Я использую Laravel для своего бэкэнда API. Интерфейс — это стороннее SPA.
Я только что тестировал свою конечную точку входа (POST) с помощью Thunder Client (XHR). Если вызов входа в систему успешен один раз, любые последующие вызовы конечной точки входа вызывают перенаправление на корневой 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 промежуточного программного обеспечения решает проблему:
if ($request->expectsJson())
return response()->json(['message' => 'authenticated.'], 200);
Эта проблема и ее исправление, по-видимому, хорошо известны уже много лет. Однако тот факт, что это промежуточное программное обеспечение теперь является частью платформы Laravel 11 и находится в каталоге handle, означает, что мне придется добавить эту строку вручную в развертывание, а также позаботиться о том, чтобы она не перезаписывалась во время обновлений. Не понимаю, почему Laravel не добавил эту простую проверку в последние несколько основных версий.
@krisgjika: Sanctum поддерживает сеансы на основе файлов cookie в дополнение к входу в систему на основе токенов старого стиля. Я также понял, что проблема с перенаправлением действительно является упущением на уровне фреймворка в классе RedirectIfAuthenticated . Смотрите мое обновление.
да, перенаправление происходит в промежуточном программном обеспечении RedirectIfAuthenticated, применяемом псевдонимом guest. Вы можете попробовать объявить новый псевдоним гостя laravel.com/docs/11.x/middleware#middleware-aliases с помощью своего собственного промежуточного программного обеспечения, которое расширяет RedirectIfAuthenticated, и перезаписать то, что вам нужно.
это или, если невозможно перезаписать промежуточное программное обеспечение для указанного псевдонима, создайте новый псевдоним и используйте его вместо гостя
@krisgjika: Это хорошая идея, и я обдумываю ее. Чего я не могу понять, так это как внедрить это новое промежуточное программное обеспечение в конвейер Fortify. Конвейер по умолчанию, показанный в документации, не имеет RedirectIfAuthenticated промежуточного программного обеспечения, но мы знаем, что он есть в реальном конвейере.
вы пытались объявить псевдоним guest? не перезаписал ли он существующий псевдоним?
@krisgjika: Решение найдено. Смотрите мой ответ. И большое спасибо за вклад.






Решение найдено. Вам нужен маршрут с именем home или dashboard в api.php. Как только вы определите этот маршрут, любые последующие вызовы login будут корректно возвращать данные JSON (возвращенные маршрутом home), и никаких перенаправлений не произойдет.
Как упоминалось в вопросе, проблема с перенаправлением возникла только тогда, когда пользователь уже вошел в систему (и был установлен файл cookie). Раньше неаутентифицированные пользователи получали правильный ответ JSON при первом login звонке. Добавление маршрута /home решает эту проблему.
Похоже, что эти имена жестко запрограммированы в промежуточном программном обеспечении в Laravel 11. Поскольку промежуточное программное обеспечение теперь является частью фреймворка, вы не можете изменить его в пользовательском коде. Обратите внимание, что ранее я также пытался перезаписать промежуточное ПО по умолчанию своей собственной реализацией, но не смог заставить его работать.
основываясь на предложении Криса Гжики, вы можете создать 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]);
})
При этом вы можете заменить промежуточное программное обеспечение «гость» на этот «json_guest» в файлах маршрутов.
// 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');
});
Импортировать use Illuminate\Auth\Middleware\RedirectIfAuthenticated;
Я также столкнулся с этой проблемой, начиная с Laravel 4 и 10, это никогда не было проблемой, поскольку мы все равно привыкли модифицировать класс RedirectIfAuthenticated для наших нужд.
Решение этой проблемы немного сложное, но его можно сделать, создав собственное промежуточное программное обеспечение, которое расширяет основной класс RedirectIfAuthenticated с помощью функции handle и переопределяет ее. Интересно, почему команда Laravel не реализовала это внутри себя, ведь в святилище есть резервная проверка для запросов на основе токенов на предъявителя.
Чтобы заставить Sanctum работать с его функциями, а также иметь измененный ответ JSON при выполнении запросов JSON, необходимо выполнить следующее:
// 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);
}
}
// 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,
]);
})
Вы можете изменить это поведение, используя метод redirectGuestsTo файла bootstrap/app.php вашего приложения: 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'));
})
обычно конечная точка входа в API должна возвращать токен, и повторный вызов должен просто создавать новый токен, а не перенаправлять