2016-05-12 13 views
16

HintergrundZuul als Authentifizierungs-Gateway

Ich möchte mit dem Design in diesem article präsentiert umzusetzen.

Es kann durch das Diagramm unten zusammengefasst werden: Security Architecture

  1. Der Kunde zuerst mit dem IDP (OpenID Connect/OAuth2)
  2. Die IDP gibt einen Zugriffstoken (opak Token ohne User-Info authentifiziert)
  3. der Kunde macht
  4. der API-Gateway stellt eine Anfrage an den IDP mit dem Access Token
  5. ein Anruf das Zugriffstoken im Header Authorization über den API-Gateway verwenden
  6. Der IDP überprüft, dass der Access Token gültig ist und gibt Benutzerinformationen im JSON-Format zurück
  7. Das API-Gateway speichert die Benutzerinformationen in einem JWT und signiert sie mit einem privaten Schlüssel. Die JWT wird dann an den Downstream-Dienst weitergeleitet, der die JWT mit dem öffentlichen Schlüssel
  8. überprüft, ob ein Dienst einen anderen Dienst aufrufen muß, die Anforderung erfüllen sie die JWT gibt, entlang dem die Authentifizierung und Autorisierung für die Anfrage
dient

Was ich bisher

ich habe die meisten getan werden:

  • Frühling Wolke als globaler Rahmen
  • Frühling Boot einzelne Dienste
  • Netflix Zuul als die API-Gateway

ich auch ein Zuul PRE-Filter, der für eine Access-Token prüft geschrieben haben, in Kontakt mit der IDP und erstellen JWT zu starten. Der JWT wird dann zum Header für die Anfrage hinzugefügt, die an den Downstream-Dienst weitergeleitet wird.

Problem

Jetzt ist meine Frage an Zuul und seine Filter ganz spezifisch. Wenn die Authentifizierung aus irgendeinem Grund im API-Gateway fehlschlägt, wie kann ich das Routing stoppen und direkt mit einem 401 antworten, ohne die Filterkette fortzusetzen und den Anruf weiterzuleiten?

Im Moment, wenn die Authentifizierung fehlschlägt, fügt der Filter die JWT nicht zur Kopfzeile hinzu, und die 401 kommt vom nachgeschalteten Dienst. Ich hatte gehofft, dass mein Gateway diesen unnötigen Anruf verhindern könnte.

Ich versuchte zu sehen, wie ich com.netflix.zuul.context.RequestContext verwenden konnte, um dies zu tun, aber die Dokumentation ist ziemlich schlecht und ich konnte keinen Weg finden.

+0

Warum sind Sie nicht mit Spring Cloud Security für diesen? das bietet dieses out-of-the-box für afaik. –

+0

@M.Deinum Ich dachte nicht, dass ich genug Kontrolle haben könnte, um dieses spezielle Design zu implementieren. Ich brauche Zugangstoken außerhalb meines gesicherten Netzwerks und JWT innerhalb. Ich habe nicht viel Erfahrung mit Spring Cloud Sicherheit. Glaubst du, ich könnte damit mein Design erreichen? – phoenix7360

+0

Spring Cloud Security leitet das gleiche Token nur an die Downstream-Dienste weiter. Es ist nicht in der Lage, Token wie @ phoenix7360 zu tauschen oder zu verbessern. Es ist jedoch ein vernünftiger Baustein, von dem aus gearbeitet werden kann. –

Antwort

9

Sie könnten versuchen, setSendZuulResponse(false) im aktuellen Kontext zu setzen. Dies sollte die Anfrage nicht weiterleiten. Sie könnten auch removeRouteHost() aus dem Kontext aufrufen, was das gleiche erreichen würde. Sie könnten setResponseStatusCode verwenden, um den 401-Statuscode festzulegen.

0

Ich weiß, ich bin sehr spät zu beantworten Sie können mit Vorfilter von Zuul nähern. Die Schritte, die Sie befolgen müssen, finden Sie unten.

//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() wird den RequestContext für die aktuelle Thread-Anfrage zurücksetzen. und Sie können einen Antwortstatuscode angeben. In

3

den folgenden in Ihrer run-Methode, wird es dieses Problem lösen

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