16

ContexteEn utilisant Zuul comme une passerelle d'authentification

Je veux mettre en œuvre la conception présentée dans ce article.

Il peut se résumer par le schéma ci-dessous: Security Architecture

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

ce que j'ai jusqu'à présent

J'ai la plupart de ce fait en utilisant:

  • nuage de printemps en tant que cadre global
  • botte de printemps pour lancer des services individuels
  • Netflix Zuul comme la passerelle API

J'ai aussi écrit un filtre Zuul PRE qui vérifie un jeton d'accès, en contact avec le IDP et créer un JWT. Le JWT est ensuite ajouté à l'en-tête de la demande transmise au service en aval.

Problème

Maintenant, ma question est tout à fait spécifique à Zuul et ses filtres. Si l'authentification échoue dans la passerelle API pour une raison quelconque, comment puis-je arrêter le routage et répondre directement avec un 401 sans poursuivre la chaîne de filtrage et transférer l'appel? Au moment où 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 je pourrais utiliser com.netflix.zuul.context.RequestContext pour ce faire mais la documentation est assez pauvre et je n'ai pas pu trouver un moyen.

+0

Pourquoi ne vous utilisez Cloud Security Spring pour cela? cela fournit cette out-of-the-box pour afaik. –

+0

@ M.Deinum Je ne pensais pas que je pouvais avoir assez de contrôle pour mettre en œuvre cette conception spécifique. J'ai besoin d'avoir un jeton d'accès en dehors de mon réseau sécurisé et de JWT à l'intérieur. Je n'ai pas beaucoup d'expérience avec la sécurité Spring Cloud. Pensez-vous que je pourrais l'utiliser pour réaliser mon design? – phoenix7360

+0

Spring Cloud Security ne transmet que le même jeton aux services descendants. Il n'a pas la capacité d'échanger ou d'améliorer les jetons comme @ phoenix7360 cherche à faire. Cependant, c'est un élément de base raisonnable à partir de laquelle travailler. –

Répondre

9

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

0

Je sais que je suis très en retard pour répondre Vous pouvez vous approcher avec préfiltre de zuul. Les étapes à suivre sont indiquées 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() se réinitialise le RequestContext pour les fils actuels demande active. et vous pouvez fournir un code d'état de réponse.

3

Ajouter les éléments suivants dans votre méthode d'exécution, il va résoudre ce problème

ctx.setSendZuulResponse(false); 
ctx.setResponseStatusCode(401);