Laravel 11: Как контролировать поведение RedirectIfAuthenticated?

Это 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 не добавил эту простую проверку в последние несколько основных версий.

обычно конечная точка входа в API должна возвращать токен, и повторный вызов должен просто создавать новый токен, а не перенаправлять

kris gjika 25.03.2024 12:09

@krisgjika: Sanctum поддерживает сеансы на основе файлов cookie в дополнение к входу в систему на основе токенов старого стиля. Я также понял, что проблема с перенаправлением действительно является упущением на уровне фреймворка в классе RedirectIfAuthenticated . Смотрите мое обновление.

dotNET 26.03.2024 01:59

да, перенаправление происходит в промежуточном программном обеспечении RedirectIfAuthenticated, применяемом псевдонимом guest. Вы можете попробовать объявить новый псевдоним гостя laravel.com/docs/11.x/middleware#middleware-aliases с помощью своего собственного промежуточного программного обеспечения, которое расширяет RedirectIfAuthenticated, и перезаписать то, что вам нужно.

kris gjika 26.03.2024 09:22

это или, если невозможно перезаписать промежуточное программное обеспечение для указанного псевдонима, создайте новый псевдоним и используйте его вместо гостя

kris gjika 26.03.2024 10:06

@krisgjika: Это хорошая идея, и я обдумываю ее. Чего я не могу понять, так это как внедрить это новое промежуточное программное обеспечение в конвейер Fortify. Конвейер по умолчанию, показанный в документации, не имеет RedirectIfAuthenticated промежуточного программного обеспечения, но мы знаем, что он есть в реальном конвейере.

dotNET 26.03.2024 11:04

вы пытались объявить псевдоним guest? не перезаписал ли он существующий псевдоним?

kris gjika 26.03.2024 15:23

@krisgjika: Решение найдено. Смотрите мой ответ. И большое спасибо за вклад.

dotNET 28.03.2024 09:08
Стоит ли изучать PHP в 2026-2027 годах?
Стоит ли изучать PHP в 2026-2027 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Symfony Station Communiqué - 7 июля 2023 г
Symfony Station Communiqué - 7 июля 2023 г
Это коммюнике первоначально появилось на Symfony Station .
Оживление вашего приложения Laravel: Понимание режима обслуживания
Оживление вашего приложения Laravel: Понимание режима обслуживания
Здравствуйте, разработчики! В сегодняшней статье мы рассмотрим важный аспект управления приложениями, который часто упускается из виду в суете...
Установка и настройка Nginx и PHP на Ubuntu-сервере
Установка и настройка Nginx и PHP на Ubuntu-сервере
В этот раз я сделаю руководство по установке и настройке nginx и php на Ubuntu OS.
Коллекции в Laravel более простым способом
Коллекции в Laravel более простым способом
Привет, читатели, сегодня мы узнаем о коллекциях. В Laravel коллекции - это способ манипулировать массивами и играть с массивами данных. Благодаря...
Как установить PHP на Mac
Как установить PHP на Mac
PHP - это популярный язык программирования, который используется для разработки веб-приложений. Если вы используете Mac и хотите разрабатывать...
3
7
3 091
5
Перейти к ответу Данный вопрос помечен как решенный

Ответы 5

Ответ принят как подходящий

Решение найдено. Вам нужен маршрут с именем 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;

Abdul Basit 25.05.2024 17:16

Я также столкнулся с этой проблемой, начиная с Laravel 4 и 10, это никогда не было проблемой, поскольку мы все равно привыкли модифицировать класс RedirectIfAuthenticated для наших нужд.

Решение этой проблемы немного сложное, но его можно сделать, создав собственное промежуточное программное обеспечение, которое расширяет основной класс RedirectIfAuthenticated с помощью функции handle и переопределяет ее. Интересно, почему команда Laravel не реализовала это внутри себя, ведь в святилище есть резервная проверка для запросов на основе токенов на предъявителя.

Решение

Чтобы заставить 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,
        ]);
    })

Вы можете изменить это поведение, используя метод 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'));
})

Другие вопросы по теме