2013-11-07 2 views
0

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

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

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

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

Спасибо!

ответ

2

Хорошо, после того, как я углубился в код пучка, я понял это. Проблема возникает из-за того, как плохой учетный документ обрабатывается с помощью проверки подлинности HTTP Basic Authentication Symfony. Ответ 401 Bad Credentials - это настраиваемый ответ, созданный BasicAuthenticationEntryPoint, который вызывается функцией 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 -clause в handle функция выше также объясняет, почему она работает в случае «никаких учетных данных пользователя вообще», поскольку в этом случае слушатель просто перестает пытаться аутентифицировать пользователя, и поэтому исключение будет вызываться прослушивателями брандмауэра Symfony (не совсем уверен, где точно), поэтому FOSRestBundle's AccessDeniedListener способен поймать AuthenticationException и выполнить свою задачу.

0

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

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

Затем добавить дополнительную проверку для BadCredentialsException и emmit в HttpException с желаемым кодом/сообщение аналогично для проверки AuthenticationException на Line 70.

+0

Спасибо за быстрый ответ! К сожалению, 'AccessDeniedListener' даже не кажется вызванным в случае« плохих учетных данных ». Мой пользовательский 'AccessDeniedListener' вызывается в случае« no authentication at all ». Однако, если я добавлю путь 'else' (который должен улавливать все другие исключения) в [Line 74] (https://github.com/FriendsOfSymfony/FOSRestBundle/blob/master/EventListener/AccessDeniedListener.php# L74) и вернуть некоторое произвольное 'HttpException', я все равно получаю' 401 Bad Credentials' в случае неправильной PW. Есть идеи?Может быть, у какого-то другого слушателя есть более высокий prio? – MichaelB

+1

вы можете найти других слушателей/подписчиков, используя 'app/console container: debug --tag = kernel.event_listener --show-private' - см. [** мой ответ здесь **] (http://stackoverflow.com/ вопросы/16688519/как к отладочных-тэгов-и-сервисов, сконфигурированных-в-Symfony2-сервис-контейнера). – nifr

+0

Я искал это при отладке, спасибо! К счастью, я нашел проблему, связанную с прослушивателем HTTP Basic Basic Authentication для Symfony (см. Мой ответ). – MichaelB

 Смежные вопросы

  • Нет связанных вопросов^_^