FOSRestBundle:返回“Bad Credentials”异常的JSON / XML元数据

时间:2013-11-07 12:37:36

标签: authentication symfony fosrestbundle

我正在使用FOSRestBundle作为我的REST API,到目前为止它一直是一个很棒的工具。我使用HTTP Basic Auth,在大多数情况下它工作得很好。但是,在提交错误凭据时,我遇到了bundle的异常行为问题。处理异常时(通过集成的身份验证处理程序或异常映射配置),bundle总是给我一个响应,其中包含正确的HTTP状态和类似于此的JSON / XML内容:

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

这很好,在完全提交无身份验证信息时也可以。但是,在提交错误凭据(例如,未知用户名或密码不正确)时,我会收到HTTP代码401错误凭据(这很好),其中包含空消息正文。相反,我会期望类似于上面的JSON。

这是我身上的错误还是配置问题?我还想知道捆绑包是如何处理这些类型的身份验证错误的,因为它会覆盖BadCredentialsException'

>在捆绑包的异常配置部分的codes部分中的状态代码似乎被忽略。

谢谢!

2 个答案:

答案 0 :(得分:2)

好吧,在深入研究捆绑代码之后,我明白了。问题是由Symfony的HTTP基本身份验证实施处理错误凭据的方式造成的。 401 Bad Credentials响应是由BasicAuthenticationEntryPoint创建的自定义响应,由BasicAuthenticationListener的{​​{1}}函数调用,在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 - 子句也解释了为什么它在“根本没有用户凭据”的情况下工作,因为在这种情况下,监听器只是停止尝试进行身份验证用户,因此Symfony的防火墙监听器会抛出异常(不太确定确切位置),因此FOSRestBundle的handle能够捕获AccessDeniedListener并执行其操作。

答案 1 :(得分:0)

您可以扩展AccessDeniedListener并告诉FOSRestBundle使用您自己的参数%fos_rest.access_denied_listener.class%的侦听器。 (service definition

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

然后添加BadCredentialsException的额外检查,并发送HttpException,其中包含与Line 70处的AuthenticationException检查类似的所需代码/消息。