Springboot两种处理跨域问题的解决办法

CORS是浏览器为防跨站脚本攻击设置的安全措施,前后端分离开发中却成阻碍。本文介绍Spring Boot解决跨域问题的思路,包括浏览器跨站请求流程和Spring Boot处理请求流程。还给出无Spring Security时的两种常用方案,以及有Spring Security时的处理方式和Spring Security自身处理CORS的便捷方法。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

CORS是Web浏览器为了防止跨站脚本攻击而设置的一种安全保护措施,但前后端分离开发流行后,浏览器的这种保护措施某种程度上反而成了绊脚石。

跨域问题如何解决?Springboot解决CORS我们弄明白这两个点就行:

1)浏览器发送跨站请求时,在发送POST请求之前它会先发送一个OPTION请求试探一下服务器的反应。如果服务器支持CORS请求,那服务器返回的响应头(headers)中就会包含浏览器所需的一些header信息(Access-Control-Allow-Origin、Access-Control-Allow-Methods、Access-Control-Allow-Headers、Access-Control-Allow-Credentials),然后浏览器就发送POST请求;如果服务器不支持CORS的话就不会返回那些header信息,收不到所需的header浏览器终止发送POST请求,然后报出CORS error。

2)Springboot处理客户端请求的流程如图所示:请求从浏览器发出,最先通过过滤器链,然后通过Dispatcher Servlet,然后通过拦截器,最后才到达处理请求的控制器上。我们只要让Springboot在受到OPTIONS试探请求时,过滤器或者在拦截器上给浏览器返回一下它需要的那几个header信息就可以了。

 

通过上面两段介绍,对CORS有了解决问题的思路,有了思路那这个问题的解决方案就很多了,平时比较常用的两种方式如下:(请注意:这是没有Spring Security的情况下

第一种:在控制器上添加注解CrossOrigin让CorsInterceptor拦截器来处理:

@RestController
//写在类头上的话,对所有方法有效
@CrossOrign(origins = "允许跨域的域名",allowCredentials = "true",allowedHeaders = "*")
public class TestController {
    //写在方法头上的话,对当前方法有效    
    @CrossOrign(origins = "允许跨域的域名",allowCredentials = "true",allowedHeaders = "*")
    @RequestMapping(value = "/api/test",method= RequestMethod.POST)
    public ResponseEntity test(){
        return ResponseEntity.ok("test");
    }
}

控制器加上这个注解后,Springboot就会激活CorsInterceptor拦截器来处理Cors问题。如果每个控制器上一个一个的加注解觉得麻烦的话,可以在MvcConfigurer上一次性设置一下,让其全局有效就可以了:

@Configuration
public class MyMvcConfig implements WebMvcConfigurer{
    @Override
    public void addCorsMappings(CorsRegistry registry) {
        registry.addMapping("/**") //对那些请求路径有效
                .allowedOrigins("*")
                .allowedHeaders("*")
                .allowedHeaders("*")
                .allowCredentials(true)
                .maxAge(10000);
    }
}

第二种:在第一种解决方式中我们用interceptor解决问题,接下来我们用Filter解决这个问题。我们Filters过滤器链中手动添加一个处理CORS的Filter就可以,代码如下:

@Component
@Order(Ordered.HIGHEST_PRECEDENCE)
public class RestCorsFilter implements Filter {

    public RestCorsFilter() {
    }

    @Override
    public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {
        HttpServletResponse response = (HttpServletResponse) res;
        HttpServletRequest request = (HttpServletRequest) req;
        response.setHeader("Access-Control-Allow-Origin", "*");
        response.setHeader("Access-Control-Allow-Credentials","true");
        response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS");
        response.setHeader("Access-Control-Max-Age", "31536000");
        response.setHeader("Access-Control-Allow-Headers", "*");
        if ("OPTIONS".equalsIgnoreCase(request.getMethod())) {
            response.setStatus(HttpServletResponse.SC_OK);
        } else {
            chain.doFilter(req, res);
        }
    }

    @Override
    public void init(FilterConfig filterConfig) {
    }

    @Override
    public void destroy() {
    }
}

这里比较重要的注解有两个@Component和@Order,其中Component大家应该都懂不用多说,那Order是干什么的呢?因为过滤器链中有很多过滤器,为了防止爱管闲事的某个过滤器拦截CORS请求,所以我们用Order(Ordered.HIGHEST_PRECEDENCE)来把我们的过滤器排到最前面,Ordered.HIGHEST_PRECEDENCE是过滤器链的最高等级排位,有这个注解的过滤器会排在最前面。

好了,接下来我们聊聊如果有Spring Security的时候会是什么样的情况

Spring Security由一堆验证授权过滤器组成,他们会以SecurityFilterChain的方式加入到我们的过滤器链:

 

如图所示,Spring Security加入后情况有了些变化(红色部分),我们刚才的第一种解决方式在这种情况下会失效,因为Spring Security会在过滤器链拦截CORS试探请求,请求无法到达Interceptor拦截器那边。而我们的第二种解决方式倒是可以继续用,因为我们给过滤器设置了最高等级的排位,他会排在在Spring Security的过滤器之前处理CORS请求。

其实Spring Security也提供了它的处理CORS的方式,而且使用起来比前面两个方式显得更优雅更专业,下面看看具体怎么处理。

第三种:Spring Security提供了非常便捷的方式让我们处理CORS,我们只要在Security Adapter 中配置一下cors就可以:

@Configuration
@EnableWebSecurity
public class SecurityTestConfig extends WebSecurityConfigurerAdapter {
    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .cors().configurationSource(corsConfigurationSource()) // 这里
                .and()
                ...
    }
    CorsConfigurationSource corsConfigurationSource(){
        CorsConfiguration corsConfiguration = new CorsConfiguration();
        corsConfiguration.setAllowCredentials(true);
        corsConfiguration.setAllowedHeaders(Arrays.asList("*"));
        corsConfiguration.setAllowedMethods(Arrays.asList("*"));
        corsConfiguration.setAllowedOrigins(Arrays.asList("*"));
        corsConfiguration.setMaxAge(3600L);
        UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
        source.registerCorsConfiguration("/**",corsConfiguration);
        return source;
    }
}

我们在http security config方法中添加.cors(), 这会让Spring Security全局搜索可用的CORS配置,接着我们给他configurationSource让他直接用我们给的CORS配置。

这样我们的CORS就处理完了。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值