SpringBoot + Zuul + Oauth2 - OAuth2TokenRelayFilter重新授权

时间:2017-06-06 21:43:42

标签: spring-boot netflix-zuul spring-oauth2

我正在将一组Spring Boot / OAuth2 / Zuul应用程序从Spring Boot 1.3.8.RELEASE和Spring Cloud Brixton.SR6升级到Spring Boot 1.5.2.RELEASE和Spring Cloud Dalston.SR1。由于升级,我的应用程序停止工作。经过进一步审查,我发现我的SSO客户端试图通过Zuul中继请求时尝试重新授权。深入挖掘我的问题的原因是对OAuth2TokenRelayFilter所做的更改。如果令牌无法授权,则添加了代码以发送401错误,但是从我看来,这也忽略了令牌可能已经被检索并且用户已经被授权的事实

要让我的应用程序运行,我必须通过将以下内容添加到applications.properties来禁用OAuth2TokenRelayFilter。

zuul.OAuth2TokenRelayFilter.pre.disable=true

然后我对OAuth2TokenRelayFilter进行了一些小修改,并将其保存为MyOAuth2TokenRelayFilter。我只是将以下内容添加到getAccessToken方法中。

String value = (String) ctx.get(ACCESS_TOKEN);
if ( value != null && !value.isEmpty()){
            return value ;
        }

完整代码(再次简单地从原始代码修改)。

public class MyOAuth2TokenRelayFilter extends ZuulFilter {

    private static final String ACCESS_TOKEN = "ACCESS_TOKEN";
    private static final String TOKEN_TYPE = "TOKEN_TYPE";
    private Map<String, Route> routes = new HashMap<String, Route>();

    private OAuth2RestOperations restTemplate;

    public MyOAuth2TokenRelayFilter(ProxyAuthenticationProperties properties) {
        this.routes = properties.getRoutes();
    }

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

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

    @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();
                if (ctx.containsKey("proxy")) {
                    String id = (String) ctx.get("proxy");
                    if (routes.containsKey(id)) {
                        if (!Route.Scheme.OAUTH2.matches(routes.get(id).getScheme())) {
                            return false;
                        }
                    }
                }
                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("authorization", ctx.get(TOKEN_TYPE) + " " + getAccessToken(ctx));
        return null;
    }

    private String getAccessToken(RequestContext ctx) {
        String value = (String) ctx.get(ACCESS_TOKEN);
        if ( value != null && !value.isEmpty()){
            return value ;
        }
        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
                    ctx.set("error.status_code", HttpServletResponse.SC_UNAUTHORIZED);
                    throw new BadCredentialsException("Cannot obtain valid access token");
                }
            }
        }
        return value;
    }

}

在我的应用程序中,大多数用户在进行zuul路由呼叫之前都已经过验证,所以我不知道在路由调用和尚未检索到令牌的情况下这是否会中断。

这是一个可行的解决方案,还是我错过了一些东西,只是掩盖了一个更大的问题?

0 个答案:

没有答案