Spring 安全更改重定向 URL 以使用 HTTPS 而不是 HTTP
Posted
技术标签:
【中文标题】Spring 安全更改重定向 URL 以使用 HTTPS 而不是 HTTP【英文标题】:Spring security change redirect URL to use HTTPS instead of HTTP 【发布时间】:2018-06-15 14:48:48 【问题描述】:我正在使用受 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-forwarded-proto
由于负载均衡器也没有将x-forwarded-proto
正确填充到HTTPS
,而是给了我HTTP
,我不能使用Spring 对它的支持。
需要通道 HTTPS
它也不起作用,因为它导致来自 Spring 的无限重定向,因为 Spring 从未收到来自 ELB
的 HTTPS 请求,尽管正确生成了 HTTPS 重定向 URL。
拦截器/过滤器
使用ServletFilter
检查响应标头Location
,如果存在,将http://
替换为https://
。
坦率地说,最后一个选项是我的最后一个选项,因为我不控制 ELB 配置。
现在的问题是我无法在 spring 重定向到 /login
URL 后拦截响应,而后者又应该重定向到 SSO URL。
我尝试了各种拦截器组合(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 标头以包含正确的协议?
感谢任何提示。
【问题讨论】:
【参考方案1】:如果您想更新 Location 标头信息,您可以尝试使用 HttpResponseInterceptor。
这是来自 google 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
【讨论】:
【参考方案2】: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
【讨论】:
以上是关于Spring 安全更改重定向 URL 以使用 HTTPS 而不是 HTTP的主要内容,如果未能解决你的问题,请参考以下文章
Azure Active Directory 中的 URL 重定向
使用Spring Social,Spring安全登录后重定向到原始URL?