SpringBoot跨域处理
@CrossOrigin(局部跨域)
- 作用在方法上
@RestController
public class IndexController {@CrossOrigin(value = "http://localhost:8082")@GetMapping("/hello")public String hello() {return "get hello";}@CrossOrigin(value = "http://localhost:8082")@PostMapping("/hello")public String hello2() {return "post hello";}
}
- 作用在类上
@CrossOrigin(origins = "http://example.com", maxAge = 3600)
@RestController
@RequestMapping("/account")
public class AccountController {@RequestMapping(method = RequestMethod.GET, path = "/{id}")public Account retrieve(@PathVariable Long id) {// ...}@RequestMapping(method = RequestMethod.DELETE, path = "/{id}")public void remove(@PathVariable Long id) {// ...}
}
WebMvcConfigurer(全局跨域)
@Configuration
public class WebMvcConfig implements WebMvcConfigurer {@Overridepublic void addCorsMappings(CorsRegistry registry) {registry.addMapping("/**").allowedHeaders("Content-Type","X-Requested-With","accept,Origin","Access-Control-Request-Method","Access-Control-Request-Headers","token").allowedMethods("*").allowedOrigins("*").allowCredentials(true);}
}
SpringSecurity跨域处理
跨域配置详解
如果使用了 Spring Security,上面的跨域配置会失效,因为请求被 Spring Security 拦截了
在项目中使用 Spring Security,我们必须采取额外的步骤确保它与 CORS 协作良好。这是因为 CORS 需要首先处理,否则,Spring Security 会在请求到达 Spring MVC 之前将其拒绝
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.cors().and()...}
}
可以配置 CORS 以覆盖默认的 Spring Security CORS 处理器。为此,我们需要添加一个 CorsConfigurationSource Bean,使用 CorsConfiguration 实例来处理 CORS 配置。如果添加了 CorsFilter Bean,http.cors() 方法就会使用 CorsFilter,否则就会使用 CorsConfigurationSource。如果两者都未配置,则使用 Spring MVC pattern inspector handler。
public class CorsConfigurer<H extends HttpSecurityBuilder<H>>extends AbstractHttpConfigurer<CorsConfigurer<H>, H> {private static final String HANDLER_MAPPING_INTROSPECTOR = "org.springframework.web.servlet.handler.HandlerMappingIntrospector";private static final String CORS_CONFIGURATION_SOURCE_BEAN_NAME = "corsConfigurationSource";private static final String CORS_FILTER_BEAN_NAME = "corsFilter";private CorsConfigurationSource configurationSource;public CorsConfigurer() {}public CorsConfigurer<H> configurationSource(CorsConfigurationSource configurationSource) {this.configurationSource = configurationSource;return this;}@Overridepublic void configure(H http) {ApplicationContext context = http.getSharedObject(ApplicationContext.class);CorsFilter corsFilter = getCorsFilter(context);if (corsFilter == null) {throw new IllegalStateException("Please configure either a " + CORS_FILTER_BEAN_NAME + " bean or a "+ CORS_CONFIGURATION_SOURCE_BEAN_NAME + "bean.");}http.addFilter(corsFilter);}private CorsFilter getCorsFilter(ApplicationContext context) {if (this.configurationSource != null) {return new CorsFilter(this.configurationSource);}// 查找是否有名为corsFilter的Bean对象boolean containsCorsFilter = context.containsBeanDefinition(CORS_FILTER_BEAN_NAME);if (containsCorsFilter) {return context.getBean(CORS_FILTER_BEAN_NAME, CorsFilter.class);}// 查找是否有名为corsConfigurationSource的Bean对象boolean containsCorsSource = context.containsBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME);if (containsCorsSource) {CorsConfigurationSource configurationSource = context.getBean(CORS_CONFIGURATION_SOURCE_BEAN_NAME, CorsConfigurationSource.class);return new CorsFilter(configurationSource);}// 查找是否有org.springframework.web.servlet.handler.HandlerMappingIntrospector该类boolean mvcPresent = ClassUtils.isPresent(HANDLER_MAPPING_INTROSPECTOR,context.getClassLoader());if (mvcPresent) {return MvcCorsFilter.getMvcCorsFilter(context);}return null;}static class MvcCorsFilter {private static final String HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME = "mvcHandlerMappingIntrospector";private static CorsFilter getMvcCorsFilter(ApplicationContext context) {if (!context.containsBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME)) {throw new NoSuchBeanDefinitionException(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, "A Bean named " + HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME +" of type " + HandlerMappingIntrospector.class.getName()+ " is required to use MvcRequestMatcher. Please ensure Spring Security & Spring MVC are configured in a shared ApplicationContext.");}// 获取名为mvcHandlerMappingIntrospector的Bean对象HandlerMappingIntrospector mappingIntrospector = context.getBean(HANDLER_MAPPING_INTROSPECTOR_BEAN_NAME, HandlerMappingIntrospector.class);return new CorsFilter(mappingIntrospector);}}
}
CorsConfigurationSource(全局跨域)
@Configuration
public class SpringSecurityConfig extends WebSecurityConfigurerAdapter {@Overrideprotected void configure(HttpSecurity http) throws Exception {http.authorizeRequests().anyRequest().permitAll().and().formLogin().permitAll().and().httpBasic().and()// 支持跨域访问.cors()// 可以选择配置//.configurationSource(corsConfigurationSource()).and().csrf().disable();}@Beanpublic CorsConfigurationSource corsConfigurationSource() {CorsConfiguration configuration = new CorsConfiguration();configuration.setAllowedOrigins(Arrays.asList("*"));configuration.setAllowedMethods(Arrays.asList("*"));configuration.setAllowedHeaders(Arrays.asList("*"));UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();source.registerCorsConfiguration("/**", configuration);return source;}
}
CosFilter(全局跨域)
还有一种情况就是支持 OAuth2 相关接口的跨域,比如用户要访问 OAuth2 中的 /oauth/token 等接口,可以配置一个全局的 CorsFilter 跨域过滤器类
@Configuration
public class GlobalCorsConfig {@Beanpublic CorsFilter corsFilter() {//1.添加CORS配置信息CorsConfiguration config = new CorsConfiguration();//放行哪些原始域config.addAllowedOrigin("*");//是否发送Cookie信息config.setAllowCredentials(true);//放行哪些原始域(请求方式)config.addAllowedMethod("*");//放行哪些原始域(头部信息)config.addAllowedHeader("*");//暴露哪些头部信息(因为跨域访问默认不能获取全部头部信息)config.addExposedHeader("*");//2.添加映射路径UrlBasedCorsConfigurationSource configSource = new UrlBasedCorsConfigurationSource();configSource.registerCorsConfiguration("/**", config);//3.返回新的CorsFilter.return new CorsFilter(configSource);}
}
自定义Filter(全局跨域)
public class CorsFilter extends OncePerRequestFilter {@Overrideprotected void doFilterInternal(HttpServletRequest request, HttpServletResponse response, FilterChain filterChain) throws ServletException, IOException {String orignalHeader = StringUtils.defaultIfBlank(request.getHeader("Origin"), "*");// 指定本次预检请求的有效期response.setHeader("Access-Control-Max-Age", "3600");// 服务器支持的所有头信息字段response.setHeader("Access-Control-Allow-Headers", request.getHeader("Access-Control-Request-Headers"));response.setHeader("Access-Control-Allow-Origin", orignalHeader);response.setHeader("Access-Control-Allow-Credentials", "true");response.setHeader("Access-Control-Allow-Methods", "POST, GET, OPTIONS, DELETE, PUT");filterChain.doFilter(request, response);}
}
@Configuration
public class WebMvcConfig extends WebSecurityConfigurerAdapter {@Overridepublic void configure(HttpSecurity http) throws Exception {http.addFilterBefore(new CorsFilter(), WebAsyncManagerIntegrationFilter.class);}
}