我正在使用受Spring Security SSO登录保护的Spring微服务(使用Cloudfoundry UAA)。
部署在云上的微服务可通过HTTPS
URL访问。由于HTTPS URL属于ELB(负载均衡器/ Web服务器),因此ELB对微服务的实际请求出现在HTTP
。因此Spring将用户重定向到登录页面时会在302 Location
标题中生成HTTP URL而不是HTTPS URL。
以下是流程
Browser
->(https://mymicroservice.com) Unauthenticated request (Load balancer)
->(http://internal_lan_ip:someport) Microservice
-> 302 Location http://mymicroservice.com/login
-> Browser http://mymicroservice.com/login (failed)
In short it goes from HTTPS -> HTTP -> 302 HTTP (failed as ELB doesn't serve on HTTP)
以下是我的尝试
的x转发-原
由于负载均衡器也没有正确填充x-forwarded-proto
到HTTPS
,而是它给了我HTTP
,我不能使用Spring的支持。
需要渠道HTTPS
它也不起作用,因为它导致Spring无限重定向,因为尽管正确生成了HTTPS重定向URL,但Spring从未收到来自ELB
的HTTPS请求。
拦截器/过滤
使用ServletFilter
检查回复标题Location
,如果有,请将http://
替换为https://
。
坦率地说,最后一个选项是我的最终选项,因为我不控制ELB配置。
现在的问题是,我无法在春季重定向到/login
网址后拦截响应,而后者又会重定向到SSO网址。
我尝试过拦截器的各种组合(postHandle,afterCompletion),使用Spring安全性将其注入过滤器链中的各个位置,最后将过滤器顺序设置为最低。这些都不会在重定向后拦截未经身份验证的请求。
@Component
@Order(Ordered.LOWEST_PRECEDENCE)
class RedirectUrlProtocolUpdaterFilter extends OncePerRequestFilter {
@Override
protected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain)
throws ServletException, IOException {
String locationHeader = response.getHeader("Location");
System.out.println("############ inside interceptor");
for(String name: response.getHeaderNames()) {
System.out.println(name + " : " + response.getHeader(name));
}
if(locationHeader != null && locationHeader.startsWith("http://")) {
System.out.println("###################### setting location header");
locationHeader = locationHeader.replaceAll("http://", "https://");
response.setHeader("Location", locationHeader);
}
filterChain.doFilter(request, response);
}
}
如何在过滤器/拦截器中正确拦截Spring Security的/login
重定向,并更新Location头以包含正确的协议?
任何提示都表示赞赏。
答案 0 :(得分:0)
如果您想更新位置标题信息,可以尝试使用HttpResponseInterceptor。
这是使用谷歌HttpResponseInterceptor的一个例子: https://developers.google.com/api-client-library/java/google-http-java-client/reference/1.20.0/com/google/api/client/http/HttpResponseInterceptor
其他选项来自Apache: https://hc.apache.org/httpcomponents-core-ga/httpcore/apidocs/org/apache/http/class-use/HttpResponseInterceptor.html
答案 1 :(得分:0)
SpringFramework提供了HandlerInterceptor。这将拦截所有http请求,但可用于不断检查身份验证和授权。您将必须提供3种方法的实现(如果不使用它们,则只需实现一个空方法)。然后,您可以将代码放入preHandle方法中。
public class AuthenticationInterceptor implements HandlerInterceptor {
@Override
public boolean preHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o) throws Exception {
}
@Override
public void postHandle(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, ModelAndView modelAndView) throws Exception {
}
@Override
public void afterCompletion(HttpServletRequest httpServletRequest, HttpServletResponse httpServletResponse, Object o, Exception e) throws Exception {
}
}