Перенаправление, если авторизация запроса не удалась в 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?


person lubart    schedule 21.03.2018    source источник
comment
Пожалуйста, проверьте мой ответ ниже.   -  person Pratik Mehta    schedule 21.03.2018


Ответы (3)


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

Обновление: метод redirectTo() был обновлен, чтобы решение работало на Laravel 6.x и выше.

приложение/запросы/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");
    }
}

приложение/Exceptions/NotAuthorizedException.php

<?php

namespace App\Exceptions;

use Exception;

class NotAuthorizedException extends Exception
{
    protected $route;

    public function redirectTo($route) {
        $this->route = $route;
    
        abort(Redirect::to($route));
    }
    
    public function route() {
        return $this->route;
    }
}

и app/Exceptions/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 с.

person lubart    schedule 21.03.2018

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

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

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

И перенаправляй куда хочешь.

person Pratik Mehta    schedule 21.03.2018
comment
Спасибо за ваш ответ! Но я уже переопределяю failedAuthorization(), как вы можете видеть в моем примере. Проблема в том, что я не могу redirect() из этого метода... Похоже, мне нужно создать пользовательское исключение... - person lubart; 21.03.2018

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

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

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

  3. Все, что вам нужно сделать, это создать новый HttpResponseException() в Laravel эталонный API мы можем видеть, что его задача заключается в создании нового экземпляра исключения 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('reached controller'); в верхней части вашего метода контроллера, и он не должен срабатывать. Таким образом, вы сохраняете свой контроллер тонким и разделяете заботы :)

Заметка: запрещенный ответ() был заменен после lara 5.4 на failedAuthorization().

person dgregory    schedule 07.07.2021