Zuul 反向代理与 Keycloak 服务器
Zuul reverse proxy with Keycloak server
我正在使用 Zuul 反向代理实用程序配置 Spring 云 (Angel.SR6) 应用程序,以隐藏内部服务端口。我的 zuul(边缘)服务在 8765 端口发布,我的组织服务在 8083 端口。当我在没有安全保护的情况下访问应用程序时,一切都很顺利,http://localhost:8765/organization/organizations
returns 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
,因此正在加载的结尾 url 是 http://localhost:8083/organizations
。但我希望加载第一个请求的 url 。
我有什么选择?
最近我遇到了同样的问题。我已经解决了:
添加到 Zuul 中的 application.properties
zuul.sensitive-headers=Cookie,Set-Cookie
在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();
}
}
(从评论迁移到答案)
我最终在邮件列表中创建了 Github project in order to explain my problem to the keycloak team, and got a pull request from one of the development team members trying to help me out. Following their recommendations, I came into the conclusion that zuul is good to hide stateless services (bearer only ones), but not the ones that user directly interacts with. Here it is the whole thread。
我正在使用 Zuul 反向代理实用程序配置 Spring 云 (Angel.SR6) 应用程序,以隐藏内部服务端口。我的 zuul(边缘)服务在 8765 端口发布,我的组织服务在 8083 端口。当我在没有安全保护的情况下访问应用程序时,一切都很顺利,http://localhost:8765/organization/organizations
returns 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
,因此正在加载的结尾 url 是 http://localhost:8083/organizations
。但我希望加载第一个请求的 url 。
我有什么选择?
最近我遇到了同样的问题。我已经解决了:
添加到 Zuul 中的 application.properties
zuul.sensitive-headers=Cookie,Set-Cookie
在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(); }
}
(从评论迁移到答案)
我最终在邮件列表中创建了 Github project in order to explain my problem to the keycloak team, and got a pull request from one of the development team members trying to help me out. Following their recommendations, I came into the conclusion that zuul is good to hide stateless services (bearer only ones), but not the ones that user directly interacts with. Here it is the whole thread。