Pergunta

Estou usando o Fosrestbundle para minha API REST e até agora tem sido uma ótima ferramenta. Eu uso o HTTP Basic Auth e, na maioria dos casos, funciona muito bem. No entanto, tenho problemas com o comportamento de exceção do pacote quando as más credenciais são enviadas. Ao lidar com exceções (por meio dos manipuladores de autenticação integrados ou da configuração de mapeamento de exceção), o pacote sempre me dá uma resposta com o status HTTP correto e o conteúdo JSON/XML semelhante a este:

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

Isso é bom, também funciona quando sem autenticação As informações são enviadas. No entanto, ao enviar más credenciais (por exemplo, nome de usuário desconhecido ou senha incorreta) Eu recebo o código HTTP 401 Credenciais ruins (o que é bom) com um corpo de mensagem vazio. Em vez disso, eu esperava algo semelhante ao JSON acima.

É um problema de bug ou configuração do meu lado? Eu também adoraria saber como esses tipos de erros de autenticação são exatamente tratados pelo pacote, uma vez que substituiu o BadCredentialsExceptionCódigo de status do codes A seção da seção de configuração de exceção do pacote parece ser ignorada.

Obrigado!

Foi útil?

Solução

Tudo bem, depois de cavar um pouco mais o código do pacote, descobri. O problema resulta da maneira como as credenciais ruins são tratadas pela imementação básica de autenticação básica HTTP da Symfony. o 401 Bad Credentials A resposta é uma resposta personalizada criada por BasicAuthenticationEntryPoint, que é chamado pelo BasicAuthenticationListener's handle função, imediatamente após um AuthenticationException foi jogado na mesma função. Portanto, não há como pegar esta exceção com um ouvinte:

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));
    }
}

O ponto de entrada start A função cria a resposta personalizada, sem exceções envolvidas:

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;
}

O punho if-Cláuse no handle A função acima também explica por que funciona no caso de "nenhuma credenciais de usuário", pois nesse caso, o ouvinte apenas para de tentar autenticar o usuário e, portanto, uma exceção será lançada pelos ouvintes do Firewall de Symfony (sem muita certeza de onde exatamente), então fosrestbundle's AccessDeniedListener é capaz de pegar o AuthenticationException e fazer o que é.

Outras dicas

Você pode se estender AccessdeniedListener e diga a Fosrestbundle para usar seu próprio ouvinte com o parâmetro %fos_rest.access_denied_listener.class%. (Definição de serviço)

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

Em seguida, adicione uma verificação adicional para BadCredentialsException e Emmit an HttpException com o código/mensagem desejado semelhante ao check para autenticaçãoException em Linha 70.

Licenciado em: CC-BY-SA com atribuição
Não afiliado a StackOverflow
scroll top