Spring Security 环境下 CORS 跨域失效问题

又一篇踩坑记,记录下在Spring Security 环境下, CORS 跨域的失效问题

一、背景

    之前写过一篇文章介绍了跨域以及其解决方案,传送门,但是在目前的项目中又踩了坑,发现跨域失效。

    配置方式见下图:

        cors01.png

    项目基础框架:spring boot

    安全框架:spring security



</p>

二、原因

    看文末的参考文章(spring boot 的一个 issue),看到了一个很棒的实验(下述代码取于其中)。

    

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
@Configuration
@Order(Ordered.HIGHEST_PRECEDENCE)
public&nbsp;class&nbsp;DCorsConfiguration&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;@Bean
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;FilterRegistrationBean&nbsp;dgCorsFilter()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;UrlBasedCorsConfigurationSource&nbsp;source&nbsp;=&nbsp;new&nbsp;UrlBasedCorsConfigurationSource();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;org.springframework.web.cors.CorsConfiguration&nbsp;config&nbsp;=&nbsp;new&nbsp;org.springframework.web.cors.CorsConfiguration();
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;config.setAllowCredentials(true);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;config.addAllowedOrigin("http://localhost:5000");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;config.addAllowedHeader("*");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;config.addAllowedMethod("*");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;source.registerCorsConfiguration("/**",&nbsp;config);
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;FilterRegistrationBean&nbsp;bean&nbsp;=&nbsp;new&nbsp;FilterRegistrationBean(new&nbsp;CorsFilter(source));
&nbsp;&nbsp;&nbsp;&nbsp;}
}

    然后我们启动 spring boot 项目,观察控制台打印的过滤器 chain 的顺序便会有惊人的发现:

        cors filter 是在 spring security filter chain 之后的。

1
2
3
4
5
6
7
2016-11-23&nbsp;13:35:44.883&nbsp;&nbsp;INFO&nbsp;17404&nbsp;---&nbsp;[ost-startStop-1]&nbsp;o.s.b.w.servlet.FilterRegistrationBean&nbsp;&nbsp;&nbsp;:&nbsp;Mapping&nbsp;filter:&nbsp;&#39;characterEncodingFilter&#39;&nbsp;to:&nbsp;[/*]
2016-11-23&nbsp;13:35:44.884&nbsp;&nbsp;INFO&nbsp;17404&nbsp;---&nbsp;[ost-startStop-1]&nbsp;o.s.b.w.servlet.FilterRegistrationBean&nbsp;&nbsp;&nbsp;:&nbsp;Mapping&nbsp;filter:&nbsp;&#39;hiddenHttpMethodFilter&#39;&nbsp;to:&nbsp;[/*]
2016-11-23&nbsp;13:35:44.884&nbsp;&nbsp;INFO&nbsp;17404&nbsp;---&nbsp;[ost-startStop-1]&nbsp;o.s.b.w.servlet.FilterRegistrationBean&nbsp;&nbsp;&nbsp;:&nbsp;Mapping&nbsp;filter:&nbsp;&#39;httpPutFormContentFilter&#39;&nbsp;to:&nbsp;[/*]
2016-11-23&nbsp;13:35:44.884&nbsp;&nbsp;INFO&nbsp;17404&nbsp;---&nbsp;[ost-startStop-1]&nbsp;o.s.b.w.servlet.FilterRegistrationBean&nbsp;&nbsp;&nbsp;:&nbsp;Mapping&nbsp;filter:&nbsp;&#39;OAuth2ClientContextFilter&#39;&nbsp;to:&nbsp;[/*]
2016-11-23&nbsp;13:35:44.884&nbsp;&nbsp;INFO&nbsp;17404&nbsp;---&nbsp;[ost-startStop-1]&nbsp;o.s.b.w.servlet.FilterRegistrationBean&nbsp;&nbsp;&nbsp;:&nbsp;Mapping&nbsp;filter:&nbsp;&#39;requestContextFilter&#39;&nbsp;to:&nbsp;[/*]
2016-11-23&nbsp;13:35:44.887&nbsp;&nbsp;INFO&nbsp;17404&nbsp;---&nbsp;[ost-startStop-1]&nbsp;.s.DelegatingFilterProxyRegistrationBean&nbsp;:&nbsp;Mapping&nbsp;filter:&nbsp;&#39;springSecurityFilterChain&#39;&nbsp;to:&nbsp;[/*]
2016-11-23&nbsp;13:35:44.887&nbsp;&nbsp;INFO&nbsp;17404&nbsp;---&nbsp;[ost-startStop-1]&nbsp;o.s.b.w.servlet.FilterRegistrationBean&nbsp;&nbsp;&nbsp;:&nbsp;Mapping&nbsp;filter:&nbsp;&#39;corsFilter&#39;&nbsp;to:&nbsp;[/*]

    所以,问题很清晰了,问题在于 spring security 的 过滤器链,我们只需要将手动创建的跨域 filter 置于 spring security filter chain 之前即可。




三、解决

    ① 写过滤器

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
/**
&nbsp;*&nbsp;@Author:&nbsp;Jet
&nbsp;*&nbsp;@Description:&nbsp;手动生成过滤器,目的是跨域
&nbsp;*&nbsp;@Date:&nbsp;2018/5/23&nbsp;16:55
&nbsp;*/
public&nbsp;class&nbsp;WebSecurityCorsFilter&nbsp;implements&nbsp;Filter&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;init(FilterConfig&nbsp;filterConfig)&nbsp;throws&nbsp;ServletException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;doFilter(ServletRequest&nbsp;request,&nbsp;ServletResponse&nbsp;response,&nbsp;FilterChain&nbsp;chain)&nbsp;throws&nbsp;IOException,&nbsp;ServletException&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;HttpServletResponse&nbsp;res&nbsp;=&nbsp;(HttpServletResponse)&nbsp;response;
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.setHeader("Access-Control-Allow-Origin",&nbsp;"*");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.setHeader("Access-Control-Allow-Methods",&nbsp;"POST,&nbsp;GET,&nbsp;OPTIONS,&nbsp;DELETE,&nbsp;PUT");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.setHeader("Access-Control-Max-Age",&nbsp;"3600");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;res.setHeader("Access-Control-Allow-Headers",&nbsp;"Authorization,&nbsp;Content-Type,&nbsp;Accept,&nbsp;x-requested-with,&nbsp;Cache-Control");
&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;&nbsp;chain.doFilter(request,&nbsp;res);
&nbsp;&nbsp;&nbsp;&nbsp;}
&nbsp;&nbsp;&nbsp;&nbsp;@Override
&nbsp;&nbsp;&nbsp;&nbsp;public&nbsp;void&nbsp;destroy()&nbsp;{
&nbsp;&nbsp;&nbsp;&nbsp;}
}

    ② 将跨域的过滤器置于 spring security filter chain 之前

        见下图红框中代码

1
.and().addFilterBefore(new&nbsp;WebSecurityCorsFilter(),&nbsp;ChannelProcessingFilter.class)&nbsp;//&nbsp;保证跨域的过滤器首先触发


cors02.png


四、小结

    spring boot 这种用于快速开发 java 项目的轮子,使用很便捷,大大加快了前期开发的效率,但是,正因为其采用了大量的默认配置,有时候碰上问题的时候,我们需要大肆翻源码,逛论坛,找解决帖,双刃剑呐。

    正如此文所描述的使用 spring security 的过程中碰到的跨域的坑,不下点功夫,着实难解决。

    其实开发中还遇到过 spring security 带来的 iframe 的问题、HSTS 问题等,暂不赘述。

    

    参考:https://github.com/spring-projects/spring-boot/issues/5834








------ 本文结束 感谢阅读 ------
0%