2016-05-24 6 views
4

Ich versuche, ein einfaches API-Gateway mit Spring Boot SSO + Zuul. Ich muss OAuth-Bereiche in Header übersetzen, die von einem anderen Back-End-Dienst weiter verwendet werden, um RBAC basierend auf Headern auszuführen.Wie Abrufen von Bereichen von OAuth-Token in Spring boot SSO + zuul

Ich benutze diesen CustomOAuth2TokenRelayFilter, der im Wesentlichen Header vor dem Senden an das Backend setzt. Mein Problem ist, wie bekomme ich Bereiche aus dem aktuellen Token. Die Klasse OAuth2AuthenticationDetails stellt den Token-Wert zur Verfügung, stellt jedoch die Bereiche nicht bereit.

Ich bin mir nicht sicher, wie man die Bereiche darin erhalten kann.

Unten ist die Gewohnheit Zuul Filter, die vor allem aus https://github.com/spring-cloud/spring-cloud-security/blob/master/spring-cloud-security/src/main/java/org/springframework/cloud/security/oauth2/proxy/OAuth2TokenRelayFilter.java

import com.netflix.zuul.ZuulFilter; 
import com.netflix.zuul.context.RequestContext; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.security.authentication.BadCredentialsException; 
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.context.SecurityContextHolder; 
import org.springframework.security.oauth2.client.OAuth2RestOperations; 
import org.springframework.security.oauth2.provider.OAuth2Authentication; 
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; 
import org.springframework.stereotype.Component; 

@Component 
    public class CustomOAuth2TokenRelayFilter extends ZuulFilter { 

     private static Logger LOGGER = LoggerFactory.getLogger(CustomOAuth2TokenRelayFilter.class); 

     private static final String ACCESS_TOKEN = "ACCESS_TOKEN"; 
     private static final String TOKEN_TYPE = "TOKEN_TYPE"; 

     private OAuth2RestOperations restTemplate; 


     public void setRestTemplate(OAuth2RestOperations restTemplate) { 
      this.restTemplate = restTemplate; 
     } 


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

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

     @Override 
     public boolean shouldFilter() { 
      Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 

      if (auth instanceof OAuth2Authentication) { 
       Object details = auth.getDetails(); 
       if (details instanceof OAuth2AuthenticationDetails) { 
        OAuth2AuthenticationDetails oauth = (OAuth2AuthenticationDetails) details; 
        RequestContext ctx = RequestContext.getCurrentContext(); 

        LOGGER.debug ("role " + auth.getAuthorities()); 

        LOGGER.debug("scope", ctx.get("scope")); // How do I obtain the scope ?? 


        ctx.set(ACCESS_TOKEN, oauth.getTokenValue()); 
        ctx.set(TOKEN_TYPE, oauth.getTokenType()==null ? "Bearer" : oauth.getTokenType()); 
        return true; 
       } 
      } 
      return false; 
     } 

     @Override 
     public Object run() { 
      RequestContext ctx = RequestContext.getCurrentContext(); 
      ctx.addZuulRequestHeader("x-pp-user", ctx.get(TOKEN_TYPE) + " " + getAccessToken(ctx)); 
      return null; 
     } 

     private String getAccessToken(RequestContext ctx) { 
      String value = (String) ctx.get(ACCESS_TOKEN); 
      if (restTemplate != null) { 
       // In case it needs to be refreshed 
       OAuth2Authentication auth = (OAuth2Authentication) SecurityContextHolder 
         .getContext().getAuthentication(); 
       if (restTemplate.getResource().getClientId() 
         .equals(auth.getOAuth2Request().getClientId())) { 
        try { 
         value = restTemplate.getAccessToken().getValue(); 
        } 
        catch (Exception e) { 
         // Quite possibly a UserRedirectRequiredException, but the caller 
         // probably doesn't know how to handle it, otherwise they wouldn't be 
         // using this filter, so we rethrow as an authentication exception 
         throw new BadCredentialsException("Cannot obtain valid access token"); 
        } 
       } 
      } 
      return value; 
     } 

    } 

Antwort

7

Sie die OAuth2ClientContext in Ihren Filter injizieren könnte, und oAuth2ClientContext.getAccessToken().getScope() genommen verwenden, um die Bereiche abzurufen.

OAuth2ClientContext ist eine sitzungsspezifische Bean, die das aktuelle Zugriffstoken und den gespeicherten Status enthält.

Wenn wir also, dass auf Ihr Beispiel anwenden, würde es so aussehen:

import com.netflix.zuul.ZuulFilter; 
import com.netflix.zuul.context.RequestContext; 
import org.slf4j.Logger; 
import org.slf4j.LoggerFactory; 
import org.springframework.beans.factory.annotation.Autowired; 
import org.springframework.security.authentication.BadCredentialsException; 
import org.springframework.security.core.Authentication; 
import org.springframework.security.core.context.SecurityContextHolder; 
import org.springframework.security.oauth2.client.OAuth2ClientContext; 
import org.springframework.security.oauth2.client.OAuth2RestOperations; 
import org.springframework.security.oauth2.provider.OAuth2Authentication; 
import org.springframework.security.oauth2.provider.authentication.OAuth2AuthenticationDetails; 
import org.springframework.stereotype.Component; 

@Component 
public class CustomOAuth2TokenRelayFilter extends ZuulFilter { 

    private static Logger LOGGER = LoggerFactory.getLogger(CustomOAuth2TokenRelayFilter.class); 

    private static final String ACCESS_TOKEN = "ACCESS_TOKEN"; 
    private static final String TOKEN_TYPE = "TOKEN_TYPE"; 

    private OAuth2RestOperations restTemplate; 

    @Autowired 
    private OAuth2ClientContext oAuth2ClientContext; 

    public void setRestTemplate(OAuth2RestOperations restTemplate) { 
     this.restTemplate = restTemplate; 
    } 


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

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

    @Override 
    public boolean shouldFilter() { 
     Authentication auth = SecurityContextHolder.getContext().getAuthentication(); 

     if (auth instanceof OAuth2Authentication) { 
      Object details = auth.getDetails(); 
      if (details instanceof OAuth2AuthenticationDetails) { 
       OAuth2AuthenticationDetails oauth = (OAuth2AuthenticationDetails) details; 
       RequestContext ctx = RequestContext.getCurrentContext(); 

       LOGGER.debug ("role " + auth.getAuthorities()); 

       LOGGER.debug("scope" + oAuth2ClientContext.getAccessToken().getScope()); 

       ctx.set(ACCESS_TOKEN, oauth.getTokenValue()); 
       ctx.set(TOKEN_TYPE, oauth.getTokenType()==null ? "Bearer" : oauth.getTokenType()); 
       return true; 
      } 
     } 
     return false; 
    } 

    @Override 
    public Object run() { 
     RequestContext ctx = RequestContext.getCurrentContext(); 
     ctx.addZuulRequestHeader("x-pp-user", ctx.get(TOKEN_TYPE) + " " + getAccessToken(ctx)); 
     return null; 
    } 

    private String getAccessToken(RequestContext ctx) { 
     String value = (String) ctx.get(ACCESS_TOKEN); 
     if (restTemplate != null) { 
      // In case it needs to be refreshed 
      OAuth2Authentication auth = (OAuth2Authentication) SecurityContextHolder 
        .getContext().getAuthentication(); 
      if (restTemplate.getResource().getClientId() 
        .equals(auth.getOAuth2Request().getClientId())) { 
       try { 
        value = restTemplate.getAccessToken().getValue(); 
       } 
       catch (Exception e) { 
        // Quite possibly a UserRedirectRequiredException, but the caller 
        // probably doesn't know how to handle it, otherwise they wouldn't be 
        // using this filter, so we rethrow as an authentication exception 
        throw new BadCredentialsException("Cannot obtain valid access token"); 
       } 
      } 
     } 
     return value; 
    } 

} 
+0

Vielen Dank Riccardo abrufen können! Arbeitete perfekt. –

+1

Gibt leider null für mich zurück. Autowiring im Controller versucht. Mit Client Credentials gewähren in meiner App – sandkeks

+0

scheint wie ein Charme zu arbeiten. 3 Fragen though: in Ihrem Beispiel oben, haben Sie die 'oAuth2ClientContext'-Instanz injiziert, warum immer noch die Schwierigkeiten durch die 'Authentication'-Instanz zugreifen? Haben Sie vielleicht etwas zu Dokumentationszwecken über den Sitzungsumfang von 'OAuth2ClientContext'? Request Bereich ist wahrscheinlich sicherer mit etwas wie ein Zuul Proxy? – demaniak

3

Sie Tive von OAuth2 Token mit SecurityContextHolder und OAuth2Authentication

private static Set<String> getOAuthTokenScopes() { 
    Authentication authentication = SecurityContextHolder.getContext().getAuthentication(); 
    OAuth2Authentication oAuth2Authentication; 

    if (authentication instanceof OAuth2Authentication) { 
     oAuth2Authentication = (OAuth2Authentication) authentication; 
    } else { 
     throw new IllegalStateException("Authentication not supported!"); 
    } 

    return oAuth2Authentication.getOAuth2Request().getScope(); 
} 
+0

Dies funktionierte für mich im Gegensatz zu 'oAuth2ClientContext', die null von der 'getScopes()' Methode zurückgab. Ich konnte einfach 'OAuth2Authentication authentication' zu meiner '@ Controller'-Methodensignatur hinzufügen, was es viel einfacher machte. – jax

Verwandte Themen