【问题标题】:Zuul reverse proxy with Keycloak server带有 Keycloak 服务器的 Zuul 反向代理
【发布时间】:2016-09-16 16:31:31
【问题描述】:

我正在使用 Zuul 反向代理实用程序配置 Spring Cloud (Angel.SR6) 应用程序,以隐藏内部服务端口。我的 zuul (edge) 服务发布在 8765 端口,我的组织服务发布在 8083 端口。当我在没有安全性的情况下访问应用程序时,一切都很顺利,http://localhost:8765/organization/organizations 返回所有组织的 JSON。

但是,现在我想集成 Keycloak SSO (OAuth2) 服务器以进行授权。我在我的组织服务中添加了Spring Security adapter,并将其配置为在http://localhost:8080/auth 中进行身份验证。一切都很顺利,除了 zuul 执行的是重定向而不是代理。因此,当身份验证成功时,我会被重定向到 http://localhost:8083/organizations 而不是 http://localhost:8765/organization/organizations。这是我的浏览器请求:

这是因为 keycloak 适配器在 http://localhost:8083/sso/login 中创建了一个令牌验证端点,它从该端点执行重定向到授权服务器以验证令牌。当授权服务器确认后,重定向将发送到组织服务,路径为/organization,因此要加载的结束网址为http://localhost:8083/organizations。但我希望加载第一个请求的 url。

我有什么选择?

【问题讨论】:

  • 有一点我可以肯定的说,zuul 本身不做重定向,它只转发响应,所以如果下游服务发送重定向,zuul 会转发到浏览器。跨度>
  • @spencergibb,我知道,实际上问题出在下游服务上,它配置了一个登录端点,它重定向到 SSO 服务器。 SSO 服务器接收要重定向到的 url 作为 url 参数,例如 /auth/realm/master?redirectUri=http://localhost:8083/sso/login。因此,SSO 服务器执行重定向到该 url,该 url 也重定向到最终的 http://localhost:8083/organizations 路径。一个解决方案是仅保护 zuul 服务,因此我会将每个请求重定向到 zuul 本身,但这将涉及暴露其余服务。

标签: spring-security spring-boot spring-cloud netflix-zuul keycloak


【解决方案1】:

最近我遇到了同样的问题。我已经解决了:

  1. 添加到Zuul中的application.properties

    zuul.sensitive-headers=Cookie,Set-Cookie

  2. Zuul中引入KeycloakFilterRoute

    class KeycloakFilterRoute extends ZuulFilter {
    
    private static final String AUTHORIZATION_HEADER = "authorization";
    
    @Override
    public String filterType() {
        return "route";
    }
    
    @Override
    public int filterOrder() {
        return 0;
    }
    
    @Override
    public boolean shouldFilter() {
        return true;
    }
    
    @Override
    public Object run() {
        RequestContext ctx = RequestContext.getCurrentContext();
        if (ctx.getRequest().getHeader(AUTHORIZATION_HEADER) == null) {
            addKeycloakTokenToHeader(ctx);
        }
        return null;
    }
    
    private void addKeycloakTokenToHeader(RequestContext ctx) {
        RefreshableKeycloakSecurityContext securityContext = getRefreshableKeycloakSecurityContext(ctx);
        if (securityContext != null) {
            ctx.addZuulRequestHeader(AUTHORIZATION_HEADER, buildBearerToken(securityContext));
        }
    }
    
    private RefreshableKeycloakSecurityContext getRefreshableKeycloakSecurityContext(RequestContext ctx) {
        if (ctx.getRequest().getUserPrincipal() instanceof KeycloakAuthenticationToken) {
            KeycloakAuthenticationToken token = (KeycloakAuthenticationToken) ctx.getRequest().getUserPrincipal();
            return (RefreshableKeycloakSecurityContext) token.getCredentials();
        }
        return null;
    }
    
    private String buildBearerToken(RefreshableKeycloakSecurityContext securityContext) {
        return "Bearer " + securityContext.getTokenString();
    }
    

    }

【讨论】:

    【解决方案2】:

    (从评论迁移到回答)

    我最终创建了一个Github project,以便向 keycloak 团队解释我的问题,并收到了一位开发团队成员的拉取请求,试图帮助我。根据他们的建议,我得出的结论是 zuul 可以很好地隐藏无状态服务(仅限承载者),但不能隐藏用户直接与之交互的服务。这是邮件列表中的the whole thread

    【讨论】:

      猜你喜欢
      • 2023-04-04
      • 1970-01-01
      • 2020-09-22
      • 1970-01-01
      • 1970-01-01
      • 2018-07-08
      • 1970-01-01
      • 2017-02-08
      • 2019-10-01
      相关资源
      最近更新 更多