CORS Error: Spring Boot Multiple WebSecurityConfigurerAdapter
CORS Error: Spring Boot Multiple WebSecurityConfigurerAdapter
我的代码中有多个 WebSecurityConfigurerAdapter:
@Configuration
@Order(1)
public class BoardSecurityConf extends WebSecurityConfigurerAdapter {
private final X509BoardDetailsService x509BoardDetailsService;
public BoardSecurityConf(X509BoardDetailsService x509BoardDetailsService) {
this.x509BoardDetailsService = x509BoardDetailsService;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/board/**")
.and()
.authorizeRequests()
.antMatchers("/board/all")
.authenticated()
.anyRequest()
.permitAll()
.and()
.x509()
.subjectPrincipalRegex("CN=(.*?)(?:,|$)")
.userDetailsService(x509BoardDetailsService);
}
}
@Configuration
@Order(2)
public class UserSecurityConf extends WebSecurityConfigurerAdapter {
private final JwtRequestFilter jwtRequestFilter;
private final JwtUserDetailsService jwtUserDetailsService;
public UserSecurityConf(JwtRequestFilter jwtRequestFilter, JwtUserDetailsService jwtUserDetailsService) {
this.jwtRequestFilter = jwtRequestFilter;
this.jwtUserDetailsService = jwtUserDetailsService;
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/user/**")
.and()
.authorizeRequests()
.antMatchers("/user/authenticate")
.permitAll()
.antMatchers(HttpMethod.POST, "/user")
.permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
return new JwtAuthenticationEntryPoint();
}
}
@EnableWebSecurity
@Order(3)
public class SecurityConf extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.cors().configurationSource(corsConfigurationSource())
.and()
.csrf()
.disable();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
当我通过 ajax 请求访问我的网站时,我得到:
CORS 策略已阻止从来源 'http://localhost:8082' 访问位于 'http://localhost:8080/user/authenticate' 的 XMLHttpRequest:对预检请求的响应未通过访问控制检查:'Access-Control-Allow-Origin' header 不存在于请求的资源。
我想我的 WebSecurityConfigurerAdapters 配置有误。已经检查了 Spring 文档,但没有找到任何关于 cors 和多个 WebSecurityConfigurerAdapter 配置的信息
@编辑:
现在我得到这个异常:
java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:473) ~[spring-web-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:532) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1261) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1043) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.16.jar:5.3.16]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) ~[tomcat-embed-core-9.0.58.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.16.jar:5.3.16]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.58.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.58.jar:9.0.58]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.58.jar:9.0.58]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.58.jar:9.0.58]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.58.jar:9.0.58]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.58.jar:9.0.58]
我解决了这个问题。显然,我用作 STOMP 客户端的库 SockJS
在其 XHR 中将 withCredentials
标志设置为 true (see Issue)。设置此标志后,不允许在 Cors 上使用通配符作为 AllowedOrigin。
因此我改变了:
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
对此:
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8082", "https://localhost:8082"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
我还向每个 WebSecurityConfigurerAdapter 添加了 .cors(withDefaults())
,它自动使用来自 corsConfigurationSource()
see here
的我的 bean
我的代码中有多个 WebSecurityConfigurerAdapter:
@Configuration
@Order(1)
public class BoardSecurityConf extends WebSecurityConfigurerAdapter {
private final X509BoardDetailsService x509BoardDetailsService;
public BoardSecurityConf(X509BoardDetailsService x509BoardDetailsService) {
this.x509BoardDetailsService = x509BoardDetailsService;
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/board/**")
.and()
.authorizeRequests()
.antMatchers("/board/all")
.authenticated()
.anyRequest()
.permitAll()
.and()
.x509()
.subjectPrincipalRegex("CN=(.*?)(?:,|$)")
.userDetailsService(x509BoardDetailsService);
}
}
@Configuration
@Order(2)
public class UserSecurityConf extends WebSecurityConfigurerAdapter {
private final JwtRequestFilter jwtRequestFilter;
private final JwtUserDetailsService jwtUserDetailsService;
public UserSecurityConf(JwtRequestFilter jwtRequestFilter, JwtUserDetailsService jwtUserDetailsService) {
this.jwtRequestFilter = jwtRequestFilter;
this.jwtUserDetailsService = jwtUserDetailsService;
}
@Bean
public BCryptPasswordEncoder passwordEncoder() {
return new BCryptPasswordEncoder();
}
@Override
@Bean
public AuthenticationManager authenticationManagerBean() throws Exception {
return super.authenticationManagerBean();
}
public void configure(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(jwtUserDetailsService).passwordEncoder(passwordEncoder());
}
@Override
public void configure(HttpSecurity http) throws Exception {
http.requestMatchers()
.antMatchers("/user/**")
.and()
.authorizeRequests()
.antMatchers("/user/authenticate")
.permitAll()
.antMatchers(HttpMethod.POST, "/user")
.permitAll()
.anyRequest().authenticated()
.and()
.exceptionHandling().authenticationEntryPoint(jwtAuthenticationEntryPoint())
.and()
.sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS);
http.addFilterBefore(jwtRequestFilter, UsernamePasswordAuthenticationFilter.class);
}
@Bean
JwtAuthenticationEntryPoint jwtAuthenticationEntryPoint() {
return new JwtAuthenticationEntryPoint();
}
}
@EnableWebSecurity
@Order(3)
public class SecurityConf extends WebSecurityConfigurerAdapter {
@Override
public void configure(HttpSecurity http) throws Exception {
http
.cors().configurationSource(corsConfigurationSource())
.and()
.csrf()
.disable();
}
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
}
当我通过 ajax 请求访问我的网站时,我得到: CORS 策略已阻止从来源 'http://localhost:8082' 访问位于 'http://localhost:8080/user/authenticate' 的 XMLHttpRequest:对预检请求的响应未通过访问控制检查:'Access-Control-Allow-Origin' header 不存在于请求的资源。
我想我的 WebSecurityConfigurerAdapters 配置有误。已经检查了 Spring 文档,但没有找到任何关于 cors 和多个 WebSecurityConfigurerAdapter 配置的信息
@编辑:
现在我得到这个异常:
java.lang.IllegalArgumentException: When allowCredentials is true, allowedOrigins cannot contain the special value "*" since that cannot be set on the "Access-Control-Allow-Origin" response header. To allow credentials to a set of origins, list them explicitly or consider using "allowedOriginPatterns" instead.
at org.springframework.web.cors.CorsConfiguration.validateAllowCredentials(CorsConfiguration.java:473) ~[spring-web-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.handler.AbstractHandlerMapping.getHandler(AbstractHandlerMapping.java:532) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.DispatcherServlet.getHandler(DispatcherServlet.java:1261) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:1043) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:963) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:1006) ~[spring-webmvc-5.3.16.jar:5.3.16]
at org.springframework.web.servlet.FrameworkServlet.doGet(FrameworkServlet.java:898) ~[spring-webmvc-5.3.16.jar:5.3.16]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:655) ~[tomcat-embed-core-9.0.58.jar:4.0.FR]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:883) ~[spring-webmvc-5.3.16.jar:5.3.16]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:764) ~[tomcat-embed-core-9.0.58.jar:4.0.FR]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:227) ~[tomcat-embed-core-9.0.58.jar:9.0.58]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.58.jar:9.0.58]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:53) ~[tomcat-embed-websocket-9.0.58.jar:9.0.58]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:189) ~[tomcat-embed-core-9.0.58.jar:9.0.58]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:162) ~[tomcat-embed-core-9.0.58.jar:9.0.58]
我解决了这个问题。显然,我用作 STOMP 客户端的库 SockJS
在其 XHR 中将 withCredentials
标志设置为 true (see Issue)。设置此标志后,不允许在 Cors 上使用通配符作为 AllowedOrigin。
因此我改变了:
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Collections.singletonList("*"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
对此:
@Bean
CorsConfigurationSource corsConfigurationSource() {
CorsConfiguration configuration = new CorsConfiguration();
configuration.setAllowedOrigins(Arrays.asList("http://localhost:8082", "https://localhost:8082"));
configuration.setAllowedMethods(Collections.singletonList("*"));
configuration.setAllowedHeaders(Collections.singletonList("*"));
UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource();
source.registerCorsConfiguration("/**", configuration);
return source;
}
我还向每个 WebSecurityConfigurerAdapter 添加了 .cors(withDefaults())
,它自动使用来自 corsConfigurationSource()
see here