Domanda

Sto usando FosrestBundle per la mia API di riposo e finora è stato un ottimo strumento. Uso HTTP Basic Auth e nella maggior parte dei casi funziona bene. Tuttavia, ho problemi con il comportamento delle eccezioni del bundle quando vengono presentate credenziali cattive. Quando si gestiscono le eccezioni (tramite i gestori di autenticazione integrati o la configurazione della mappatura delle eccezioni), il pacchetto mi dà sempre una risposta con lo stato HTTP corretto e il contenuto JSON/XML simili a questo:

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

Va bene, funziona anche quando Nessuna autenticazione Le informazioni vengono inviate. Tuttavia, quando si presenta pessime credenziali (ad es. Nome utente sconosciuto o password errata) ottengo il codice HTTP 401 credenziali cattive (che va bene) con un corpo di messaggi vuoti. Invece, mi sarei aspettato qualcosa di simile al JSON sopra.

È un bug o un problema di configurazione dalla mia parte? Mi piacerebbe anche sapere come questi tipi di errori di autentica BadCredentialsExceptionCodice di stato in codes La sezione della sezione di configurazione delle eccezioni del bundle sembra essere ignorata.

Grazie!

È stato utile?

Soluzione

Va bene, dopo aver scavato un po 'di più nel codice del pacchetto, l'ho capito. Il problema deriva dal modo in cui le credenziali cattive vengono gestite dall'impegnazione di autenticazione di base HTTP di Symfony. Il 401 Bad Credentials La risposta è una risposta personalizzata creata da BasicAuthenticationEntryPoint, che è chiamato dal BasicAuthenticationListener'S handle funzione, immediatamente dopo un AuthenticationException è stato lanciato nella stessa funzione. Quindi non c'è modo di catturare questa eccezione con un ascoltatore:

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

I punti di ingresso start La funzione crea la risposta personalizzata, senza eccezioni coinvolte:

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

Il pugno if-Clause nel handle La funzione sopra spiega anche perché funziona nel caso di "nessuna credenziale dell'utente", dal momento che in quel caso, l'ascoltatore smette solo di provare ad autenticare l'utente, e quindi un'eccezione verrà lanciata dagli ascoltatori di firewall di Symfony (non è sicuro esattamente), quindi di FosrestBundle AccessDeniedListener è in grado di catturare il AuthenticationException E fai le sue cose.

Altri suggerimenti

Puoi estendersi AccessDeniedListener e dì a FosrestBundle di usare il tuo ascoltatore con il parametro %fos_rest.access_denied_listener.class%. (Definizione del servizio)

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

Quindi aggiungi un controllo aggiuntivo per BadCredentialsException ed emettere un HttpException con il codice/messaggio desiderato simile al controllo per AuthenticationException su Riga 70.

Autorizzato sotto: CC-BY-SA insieme a attribuzione
Non affiliato a StackOverflow
scroll top