0

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

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

这很好,当根本没有提交身份验证信息时它也可以工作。但是,当提交错误的凭据(例如未知的用户名或不正确的密码)时,我会收到带有空消息正文的 HTTP 代码 401 Bad credentials(这很好)。相反,我会期待与上面的 JSON 类似的东西。

这是我这边的错误还是配置问题?我也很想知道捆绑包如何准确处理这些类型的身份验证错误,因为在捆绑包的异常配置部分BadCredentialsException的部分中覆盖 ' 状态代码codes似乎被忽略了。

谢谢!

4

2 回答 2

2

好吧,在深入研究了捆绑包的代码之后,我想通了。问题是由 Symfony 的 HTTP 基本身份验证实现处理错误凭据的方式造成的。401 Bad Credentials响应是由的函数创建的自定义响应,在同一函数中抛出an 后立即BasicAuthenticationEntryPoint调用该响应。所以没有办法用监听器捕捉到这个异常:BasicAuthenticationListenerhandleAuthenticationException

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 的防火墙会抛出异常听众(不太确定到底在哪里),所以 FOSRestBundleAccessDeniedListener能够捕捉到AuthenticationException并做它的事情。

于 2013-11-07T15:40:09.300 回答
0

您可以扩展AccessDeniedListener并告诉 FOSRestBundle 使用您自己的带有参数的侦听器%fos_rest.access_denied_listener.class%。(服务定义

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

然后添加一个额外的检查BadCredentialsExceptionHttpException使用所需的代码/消息发送一个类似于第 70 行的 AuthenticationException 的检查。

于 2013-11-07T13:42:15.673 回答