Spring Boot安全性CORS
我对弹簧安全URL的CORSfilter有问题。 它不会在属于spring sec(登录/注销)的URL上设置Access-Control-Allow-Origin
和其他公开的标头,也不会被Spring Security过滤。
这是配置。
CORS:
@Configuration @EnableWebMvc public class MyWebMvcConfig extends WebMvcConfigurerAdapter { ********some irrelevant configs************ @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/*").allowedOrigins("*").allowedMethods("GET", "POST", "OPTIONS", "PUT") .allowedHeaders("Content-Type", "X-Requested-With", "accept", "Origin", "Access-Control-Request-Method", "Access-Control-Request-Headers") .exposedHeaders("Access-Control-Allow-Origin", "Access-Control-Allow-Credentials") .allowCredentials(true).maxAge(3600); } }
安全:
@Configuration @EnableWebSecurity public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and() .formLogin() .successHandler(ajaxSuccessHandler) .failureHandler(ajaxFailureHandler) .loginProcessingUrl("/authentication") .passwordParameter("password") .usernameParameter("username") .and() .logout() .deleteCookies("JSESSIONID") .invalidateHttpSession(true) .logoutUrl("/logout") .logoutSuccessUrl("/") .and() .csrf().disable() .anonymous().disable() .authorizeRequests() .antMatchers("/authentication").permitAll() .antMatchers("/oauth/token").permitAll() .antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')") .antMatchers("/user/*").access("hasRole('ROLE_USER')"); } }
因此,如果我向未被安全性监听的url发出请求,则会设置CORS标头。 Spring安全URL – 未设置。
Spring boot 1.4.1
您可以编写自己的CorsFilter,并将其添加到安全配置中,而不是使用CorsRegistry。
自定义CorsFilter类:
public class CorsFilter implements Filter { @Override public void init(FilterConfig filterConfig) throws ServletException { } @Override public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException { HttpServletResponse response = (HttpServletResponse) servletResponse; HttpServletRequest request= (HttpServletRequest) servletRequest; response.setHeader("Access-Control-Allow-Origin", "*"); response.setHeader("Access-Control-Allow-Methods", "GET,POST,DELETE,PUT,OPTIONS"); response.setHeader("Access-Control-Allow-Headers", "*"); response.setHeader("Access-Control-Allow-Credentials", true); response.setHeader("Access-Control-Max-Age", 180); filterChain.doFilter(servletRequest, servletResponse); } @Override public void destroy() { } }
安全配置类:
@Configuration @EnableWebSecurity public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter { @Bean CorsFilter corsFilter() { CorsFilter filter = new CorsFilter(); return filter; } @Override protected void configure(HttpSecurity http) throws Exception { http .addFilterBefore(corsFilter(), SessionManagementFilter.class) //adds your custom CorsFilter .exceptionHandling().authenticationEntryPoint(authenticationEntryPoint).and() .formLogin() .successHandler(ajaxSuccessHandler) .failureHandler(ajaxFailureHandler) .loginProcessingUrl("/authentication") .passwordParameter("password") .usernameParameter("username") .and() .logout() .deleteCookies("JSESSIONID") .invalidateHttpSession(true) .logoutUrl("/logout") .logoutSuccessUrl("/") .and() .csrf().disable() .anonymous().disable() .authorizeRequests() .antMatchers("/authentication").permitAll() .antMatchers("/oauth/token").permitAll() .antMatchers("/admin/*").access("hasRole('ROLE_ADMIN')") .antMatchers("/user/*").access("hasRole('ROLE_USER')"); } }
选项1(使用WebMvcConfigurer bean):
您开始使用的CORS配置不是使用Spring Boot执行此操作的正确方法。 您需要注册WebMvcConfigurer
bean。 参考这里 。
示例Spring Boot CORS配置:
@Configuration @Profile("dev") public class DevConfig { @Bean public WebMvcConfigurer corsConfigurer() { return new WebMvcConfigurerAdapter() { @Override public void addCorsMappings(CorsRegistry registry) { registry.addMapping("/**").allowedOrigins("http://localhost:4200"); } }; } }
这将为基本(无安全启动器)Spring Boot应用程序提供CORS配置。 请注意,CORS支持独立于Spring Security。
一旦引入Spring Security,您需要在安全配置中注册CORS。 Spring Security足够聪明,可以获取现有的CORS配置。
@Override protected void configure(HttpSecurity http) throws Exception { http .cors().and() ....
选项2(使用CorsConfigurationSource bean):
我描述的第一个选项实际上是从向现有应用程序添加Spring Security的角度出发的。 如果您要从一开始就添加Spring Security,那么Spring Security Docs中概述的方式涉及添加CorsConfigurationSource bean。
@EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Override protected void configure(HttpSecurity http) throws Exception { http // by default uses a Bean by the name of corsConfigurationSource .cors().and() ... } @Bean CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); configuration.setAllowedOrigins(Arrays.asList("https://example.com")); configuration.setAllowedMethods(Arrays.asList("GET","POST")); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; } }
我有一个基于React
的Web客户端,我的后端REST API正在运行Spring Boot
Ver 1.5.2
我想在运行在localhost:8080
上的客户端的所有控制器路由请求上快速启用CORS
。 在我的安全配置中,我只是添加了一个类型为FilterRegistrationBean
的@Bean
,并使其易于使用。
这是代码:
@Configuration @EnableWebSecurity @EnableGlobalMethodSecurity(prePostEnabled = true) public class AuthConfiguration extends WebSecurityConfigurerAdapter { .... .... @Bean public FilterRegistrationBean corsFilter() { final UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); CorsConfiguration config = new CorsConfiguration(); config.setAllowCredentials(true); config.addAllowedOrigin(corsAllowedOrigin); // @Value: http://localhost:8080 config.addAllowedHeader("*"); config.addAllowedMethod("*"); source.registerCorsConfiguration("/**", config); FilterRegistrationBean bean = new FilterRegistrationBean(new CorsFilter(source)); bean.setOrder(0); return bean; } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity .authorizeRequests() .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // **permit OPTIONS call to all** .... } .... .... }
您可以在此处参考Spring Boot 文档
您也可以使用拦截器实现此目的。
使用该例外可确保您结束请求的生命周期:
@ResponseStatus ( value = HttpStatus.NO_CONTENT ) public class CorsException extends RuntimeException { }
然后,在您的拦截器中,为所有OPTIONS请求设置标头并抛出exception:
public class CorsMiddleware extends HandlerInterceptorAdapter { @Override public boolean preHandle ( HttpServletRequest request, HttpServletResponse response, Object handler ) throws Exception { if (request.getMethod().equals("OPTIONS")) { response.addHeader("Access-Control-Allow-Origin", "*"); response.addHeader("Access-Control-Allow-Credentials", "true"); response.addHeader("Access-Control-Allow-Methods","GET, POST, PUT, OPTIONS, DELETE"); response.addHeader("Access-Control-Allow-Headers", "DNT,X-Mx-ReqToken,Keep-Alive,User-Agent,X-Requested-With,Authorization,If-Modified-Since,Cache-Control,Content-Type"); response.addHeader("Access-Control-Max-Age", "3600"); response.addHeader("charset", "utf-8"); throw new CorsException(); } return super.preHandle(request, response, handler); } }
最后,将拦截器应用于所有路由:
@Configuration public class MiddlewareConfig extends WebMvcConfigurerAdapter { @Override public void addInterceptors (InterceptorRegistry registry) { registry.addInterceptor(new CorsMiddleware()) .addPathPatterns("/**"); } }
如果您需要它来进行快速本地开发,只需在控制器上添加此注释即可。 (根据需要改变原因)
@CrossOrigin(origins = "http://localhost:4200", maxAge = 3600)
目前,如果启用了安全性,则默认情况下会阻止OPTIONS请求。
只需添加一个额外的bean,就可以正确处理预检请求:
@Bean public IgnoredRequestCustomizer optionsIgnoredRequestsCustomizer() { return configurer -> { List matchers = new ArrayList<>(); matchers.add(new AntPathRequestMatcher("/**", "OPTIONS")); configurer.requestMatchers(new OrRequestMatcher(matchers)); }; }
请注意,根据您的应用程序,这可能会打开它以获取潜在的攻击。
打开问题以获得更好的解决方案: https : //github.com/spring-projects/spring-security/issues/4448