web-dev-qa-db-fra.com

Utiliser Zuul comme passerelle d'authentification

Contexte

Je veux implémenter le design présenté dans cet article article .

Il peut être résumé par le diagramme ci-dessous:  Security Architecture

  1. Le client s'authentifie d'abord auprès de l'IDP (OpenID Connect/OAuth2)
  2. L'IDP renvoie un jeton d'accès (jeton opaque sans information sur l'utilisateur)
  3. Le client passe un appel via la passerelle API en utilisant le jeton d'accès dans l'en-tête d'autorisation.
  4. La passerelle API adresse une demande à l'IDP avec le jeton d'accès
  5. L'IDP vérifie que le jeton d'accès est valide et renvoie les informations de l'utilisateur au format JSON
  6. La passerelle API stocke les informations utilisateur dans un fichier JWT et le signe avec une clé privée. Le JWT est ensuite passé au service en aval qui le vérifie à l'aide de la clé publique
  7. Si un service doit appeler un autre service pour répondre à la demande, il transmet le JWT qui sert d'authentification et d'autorisation à la demande.

Ce que j'ai jusqu'à présent

J'ai surtout fait ça en utilisant:

  • Nuage de printemps en tant que cadre global
  • Spring Boot pour lancer des services individuels
  • Netflix Zuul comme passerelle API

J'ai également écrit un filtre Zuul PRE qui vérifie la présence d'un jeton d'accès, contacte l'IDP et crée un JWT. Le JWT est ensuite ajouté à l'en-tête pour la demande transmise au service en aval.

Problème

Maintenant, ma question concerne assez spécifiquement Zuul et ses filtres. Si, pour une raison quelconque, l’authentification échoue dans la passerelle d’API, comment puis-je arrêter le routage et répondre directement avec un opérateur 401 sans poursuivre la chaîne de filtrage ni transférer l’appel?

En ce moment, si l'authentification échoue, le filtre n'ajoutera pas le JWT à l'en-tête et le 401 proviendra du service en aval. J'espérais que ma passerelle pourrait empêcher cet appel inutile.

J'ai essayé de voir comment utiliser com.netflix.zuul.context.RequestContext pour faire cela, mais la documentation est assez pauvre et je ne pouvais pas trouver un moyen. 

21
phoenix7360

Vous pouvez essayer de définir setSendZuulResponse(false) dans le contexte actuel. Cela ne devrait pas acheminer la demande. Vous pouvez également appeler removeRouteHost() depuis le contexte, ce qui donnerait le même résultat. Vous pouvez utiliser setResponseStatusCode pour définir le code d'état 401.

9
mbragg02

Ajoutez ce qui suit dans votre méthode d'exécution, cela résoudra ce problème

ctx.setSendZuulResponse(false);
ctx.setResponseStatusCode(401);
4
Yongxin Zhang

Je sais que je suis très en retard pour répondre. Vous pouvez vous adresser au préfiltre de zuul. Les étapes à suivre sont décrites ci-dessous.

 //1. create filter with type pre
 //2. Set the order of filter to greater than 5 because we need to run our filter after preDecoration filter of zuul.
 @Component
 public class CustomPreZuulFilter extends ZuulFilter {

  private final Logger logger = LoggerFactory.getLogger(this.getClass());

@Override
public Object run() {
    final RequestContext requestContext = RequestContext.getCurrentContext();
    logger.info("in zuul filter " + requestContext.getRequest().getRequestURI());
    byte[] encoded;
    try {
        encoded = Base64.encode("fooClientIdPassword:secret".getBytes("UTF-8"));
        requestContext.addZuulRequestHeader("Authorization", "Basic " + new String(encoded));

        final HttpServletRequest req = requestContext.getRequest();
        if (requestContext.getRequest().getHeader("Authorization") == null
                && !req.getContextPath().contains("login")) {
            requestContext.unset();
            requestContext.setResponseStatusCode(HttpStatus.UNAUTHORIZED.value());

        } else {
              //next logic
            }
        }

    } catch (final UnsupportedEncodingException e) {
        logger.error("Error occured in pre filter", e);
    }

    return null;
}



@Override
public boolean shouldFilter() {
    return true;
}

@Override
public int filterOrder() {
    return 6;
}

@Override
public String filterType() {
    return "pre";
}

}

requestContext.unset () Réinitialise le RequestContext pour la requête active des threads actuels. et vous pouvez fournir un code de statut de réponse.

0
Vishnu KR