Перенаправить, если авторизация запроса не удалась в Laravel 5.5

Я пытаюсь перенаправить запрос, если авторизация не удалась. У меня есть следующий код:

class ValidateRequest extends Request{
    public function authorize(){
        // some logic here...
        return false;
    }

    public function rules(){ /* ... */}

    public function failedAuthorization() {
        return redirect('safepage');
    }
}

По умолчанию я перенаправлен на страницу ошибки 403, но я хотел бы указать какой-то конкретный маршрут. Я заметил этот метод failedAuthorization() работает, но redirect() метод не работает...

Ранее этот код хорошо работал с Laravel 5.1, но я использовал forbiddenResponse() способ перенаправить неправильный запрос. Как я могу это исправить с новой версией LTS?

4 ответа

Решение

Похоже, это невозможно redirect() прямо из обычая ValidateRequest учебный класс. Единственное решение, которое я нашел, - это создать пользовательское исключение и обработать его в классе Handler. Итак, теперь он работает со следующим кодом:

приложение / Запросы /ValidateRequest.php

class ValidateRequest extends Request{
    public function authorize(){
        // some logic here...
        return false;
    }

    public function rules(){
        return [];
    }

    public function failedAuthorization() {
        $exception = new NotAuthorizedException('This action is unauthorized.', 403);

        throw $exception->redirectTo("safepage");
    }
}

Приложение / Исключения /NotAuthorizedException.php

<?php

namespace App\Exceptions;

use Exception;

class NotAuthorizedException extends Exception
{
    protected $route;

    public function redirectTo($route) {
        $this->route = $route;

        return $this;
    }

    public function route() {
        return $this->route;
    }
}

и приложение / Исключения /Handler.php

...
public function render($request, Exception $exception){
    ...

    if($exception instanceof NotAuthorizedException){
            return redirect($exception->route());
        }

    ...
}

Итак, это работает, но гораздо медленнее, чем я ожидал... Простое измерение показывает, что обработка и перенаправление занимают 2,1 с, но с Laravel 5.1 то же действие (и тот же код) занимает всего 0,3 с.

Добавление NotAuthorizedException::class к $dontReport собственность вообще не помогает...

Обновить

Работает намного быстрее с php 7.2, занимает 0,7 с

Если вы повторно посещаете эту ветку, потому что в 2021 году вы хотите перенаправить после неудачной авторизации, вот что вы можете сделать:

  1. Вы не можете перенаправить из метода failedAuthorization(), потому что ожидается, что он вызовет исключение (проверьте метод в базовом классе FormRequest, который вы расширяете), побочным эффектом изменения типа возврата является запрос $, попадающий в контроллер, а не обрабатываемый на уровне авторизации FormRequest.

  2. Вам не нужно создавать собственный класс исключений, а также вмешиваться в основные файлы Laravel, например редактировать render () app / Exceptions / Handler.php, который подберет созданное вами исключение и по умолчанию отобразит мягкую страницу 403.

  3. Все, что вам нужно сделать, это выбросить новое исключение HttpResponseException(). В справочном API Laravel мы видим, что его задача - «Создать новый экземпляр исключения ответа HTTP». и это именно то, что мы хотим, верно?

Итак, нам нужно передать этому исключению $response. Мы можем передать редирект или ответ в формате JSON!

Перенаправление:

      protected function failedAuthorization()
{
    throw new HttpResponseException(response()->redirectToRoute('postOverview')
        ->with(['error' => 'This action is not authorized!']));
}

Итак, мы создаем новый экземпляр HttpResponseException и используем помощник response () , который имеет этот очень полезный метод redirectToRoute ('routeName'), который мы можем связать с известным методом with() и передать сообщение об ошибке. для отображения во внешнем интерфейсе.

JSON: навеяны этой темой

      throw new HttpResponseException(response()->json(['error' => 'Unauthorized action!'], 403));

Это оно. Вам не нужно делать ЛЮБЫЕ проверки для проверки или авторизации в вашем контроллере, все делается в фоновом режиме, прежде чем он попадет в контроллер. Вы можете проверить это, поставив dd («достигнутый контроллер»); в верхней части метода контроллера, и он не должен срабатывать. Таким образом вы сохраните свой контроллер тонким и разделите проблемы :)

Замечание: после lara 5.4 запрещенныйResponse () был заменен на failedAuthorization()

Вы можете сделать это через промежуточное ПО / политику, я думаю. Я не знаю, можете ли вы сделать это из проверки.

Вы можете переопределить функцию из FormRequest следующим образом:

   /**
     * Handle a failed authorization attempt.
     *
     * @return void
     *
     * @throws \Illuminate\Auth\Access\AuthorizationException
     */
    protected function failedAuthorization()
    {
        throw new AuthorizationException('This action is unauthorized.');
    }

И перенаправить куда хочешь.

Ответ на 2023 год (Laravel v8++):

      <?php

namespace App\Http\Requests;

class MyCustomFormRequest extends Request
{
    public function authorize()
    {
        // check your logic, and:
        throw new \Illuminate\Http\Exceptions\HttpResponseException(
            redirect()->route('your route')->with('error', 'your error')
        );
    }
}

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

The authorize()Метод запроса формы — это лишь одно из мест, где его использование имеет смысл, но сделать это можно практически откуда угодно.

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