前端:VUE,后端:spring boot
前后端跨域问题解决
问题:前端始终无法连接后端API
浏览器端报错:
Access to fetch at xxx from origin yyy has been blocked by CORS policy
请教老师,发现跨域问题要在后端解决,参考官方文档:https://www.baeldung.com/spring-cors
Cors跨域问题解决:
-
定义全局CORS设置:
-
在config目录下创建WebConfig.java,写下如下内容:
package com.example.test.config; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.servlet.config.annotation.CorsRegistry; import org.springframework.web.servlet.config.annotation.WebMvcConfigurer; @Configuration public class WebConfig implements WebMvcConfigurer { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurer() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**") // 允许所有路径 .allowedOrigins("*") // 允许所有来源 .allowedMethods("GET", "POST", "PUT", "DELETE", "OPTIONS") // 允许的HTTP方法 .allowedHeaders("*") // 允许的请求头 .allowCredentials(true) // 允许发送凭证 .maxAge(3600); // CORS预检请求的缓存时间 } }; } }
-
使用前端访问进行测试,但还是显示:
Access to fetch at 'http://localhost:8080/goods' from origin 'http://127.0.0.1:5501' has been blocked by CORS policy: No 'Access-Control-Allow-Origin' header is present on the requested resource. If an opaque response serves your needs, set the request's mode to 'no-cors' to fetch the resource with CORS disabled.
查阅资料,得知无论是使用“@CrossOrigin”还是全局cors设置,本质都是在http请求的盛恒加上“Access-Control-Allow-”标头,具体借鉴:SpringBoot 配置CORS处理前后端分离跨域配置无效问题解析 - 有来技术 - 博客园进行下一步的解决。
-
在config目录下新建CorsConfig.java,写:
package com.example.test.config; import org.springframework.boot.web.servlet.FilterRegistrationBean; import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.web.cors.CorsConfiguration; import org.springframework.web.cors.UrlBasedCorsConfigurationSource; import org.springframework.web.filter.CorsFilter; import java.util.Collections; /** * CORS资源共享配置 * * @author haoxr * @date 2023/4/17 */ @Configuration public class CorsConfig { @Bean public FilterRegistrationBean filterRegistrationBean() { CorsConfiguration corsConfiguration = new CorsConfiguration(); //1.允许任何来源 corsConfiguration.setAllowedOriginPatterns(Collections.singletonList("*")); //2.允许任何请求头 corsConfiguration.addAllowedHeader(CorsConfiguration.ALL); //3.允许任何方法 corsConfiguration.addAllowedMethod(CorsConfiguration.ALL); //4.允许凭证 corsConfiguration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", corsConfiguration); CorsFilter corsFilter = new CorsFilter(source); FilterRegistrationBean<CorsFilter> filterRegistrationBean=new FilterRegistrationBean<>(corsFilter); filterRegistrationBean.setOrder(-101); // 小于 SpringSecurity Filter的 Order(-100) 即可 return filterRegistrationBean; } }
-
主要原理: SpringSecurityFilterChain 是先于 CorsFilter 执行的(重点), 如果是跨域请求浏览器会在正式请求前发出一次预检请求(OPTIONS),判断服务器是否允许跨域。
跨域请求没到达 CorsFilter 过滤器就先被 Spring Security 的过滤器给拦截了,要知道预检 OPTIONS 请求是不带 token 的,所以响应 401 未认证的错误。预检请求失败导致后面的请求响应会被浏览器拦截。
-
解决思路:
配置 CorsFilter 优先于 SpringSecurityFilter 执行
-
解决方案:
Spring Security 过滤器是通过 SecurityFilterAutoConfiguration 的 DelegatingFilterProxyRegistrationBean 注册到 servletContext上下文,其中过滤器的顺序属性 Order 读取的 是 SecurityProperties 的默认配置也就是 -100;
SpringBoot 可以通过 FilterRegistrationBean 来对 Filter 自定义注册(排序), 设置 Order 小于 SpringSecurity 的 -100 即可。
-