Фосрестбундл:Возврат метаданных JSON / XML для исключения "Неверных учетных данных"

StackOverflow https://stackoverflow.com/questions/19836178

Вопрос

Я использую FOSRestBundle для своего REST API, и до сих пор это был отличный инструмент.Я использую HTTP Basic Auth, и в большинстве случаев это работает просто отлично.Однако у меня возникают проблемы с поведением пакета в виде исключения при отправке неверных учетных данных.При обработке исключений (с помощью встроенных обработчиков аутентификации или конфигурации сопоставления исключений) пакет всегда выдает мне ответ с правильным статусом HTTP и содержимым JSON / XML, подобным этому:

{
   "code": 401,
   "message": "You are not authenticated"
}

Это нормально, это также работает, когда нет аутентификации информация предоставляется вообще.Однако при отправке плохие учетные данные (например,неизвестное имя пользователя или неверный пароль) Я получаю HTTP-код 401 с неверными учетными данными (что нормально) с пустым телом сообщения.Вместо этого я бы ожидал чего-то похожего на приведенный выше JSON.

Это ошибка или проблема с конфигурацией на моей стороне? Я также хотел бы знать, как именно такого рода ошибки аутентификации обрабатываются пакетом, поскольку переопределение BadCredentialsExceptionкод состояния в codes раздел раздела конфигурации исключений пакета, похоже, игнорируется.

Спасибо!

Это было полезно?

Решение

Хорошо, покопавшись еще немного в коде пакета, я понял это.Проблема возникает из-за того, как неверные учетные данные обрабатываются с помощью реализации базовой аутентификации HTTP Symfony.Тот Самый 401 Bad Credentials ответ - это пользовательский ответ, созданный BasicAuthenticationEntryPoint, который вызывается BasicAuthenticationListener's handle функции, сразу после AuthenticationException был брошен в ту же функцию.Таким образом, нет никакого способа перехватить это исключение с помощью слушателя:

public function handle(GetResponseEvent $event)
{
    $request = $event->getRequest();

    if (false === $username = $request->headers->get('PHP_AUTH_USER', false)) {
        return;
    }

    if (null !== $token = $this->securityContext->getToken()) {
        if ($token instanceof UsernamePasswordToken && $token->isAuthenticated() && $token->getUsername() === $username) {
            return;
        }
    }

    if (null !== $this->logger) {
        $this->logger->info(sprintf('Basic Authentication Authorization header found for user "%s"', $username));
    }

    try {
        $token = $this->authenticationManager->authenticate(new UsernamePasswordToken($username, $request->headers->get('PHP_AUTH_PW'), $this->providerKey));
        $this->securityContext->setToken($token);
    } catch (AuthenticationException $failed) {
        $this->securityContext->setToken(null);

        if (null !== $this->logger) {
            $this->logger->info(sprintf('Authentication request failed for user "%s": %s', $username, $failed->getMessage()));
        }

        if ($this->ignoreFailure) {
            return;
        }

        $event->setResponse($this->authenticationEntryPoint->start($request, $failed));
    }
}

Точка входа находится start функция создает пользовательский ответ без каких-либо исключений:

public function start(Request $request, AuthenticationException $authException = null)
{
    $response = new Response();
    $response->headers->set('WWW-Authenticate', sprintf('Basic realm="%s"', $this->realmName));
    $response->setStatusCode(401, $authException ? $authException->getMessage() : null);

    return $response;
}

Кулак if-оговорка в handle функция выше также объясняет, почему она работает в случае "вообще нет учетных данных пользователя", поскольку в этом случае прослушиватель просто прекращает попытки аутентификации пользователя, и, следовательно, прослушиватели брандмауэра Symfony выдадут исключение (не совсем уверен, где именно), поэтому FOSRestBundle AccessDeniedListener способен уловить AuthenticationException и делать свое дело.

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

Вы можете расширить AccessDeniedListener - доступ к списку и скажите FOSRestBundle, чтобы он использовал ваш собственный прослушиватель с параметром %fos_rest.access_denied_listener.class%. (определение услуги)

parameters:
    fos_rest.access_denied_listener.class: Your\Namespace\For\AccessDeniedListener

Затем добавьте дополнительную проверку на BadCredentialsException и испускать HttpException с желаемым кодом / сообщением, похожим на исключение проверки подлинности в Строка 70.

Лицензировано под: CC-BY-SA с атрибуция
Не связан с StackOverflow
scroll top