Spring Boot集成SAML对接ADFS出现CORS错误如何阻止请求重定向
问题背景
我基于公开的SAML示例项目搭建了集成SAML实现ADFS单点登录的Spring Boot服务端,和原示例项目不同的是我使用Gradle而非Maven进行构建。
目前登录功能和其他常规功能运行正常,仅存在CORS错误,浏览器侧会出现以下三类报错:
- 情况一


- 情况二



- 直接访问对应URL时的报错

Spring服务端始终抛出相同错误,日志如下:
2021-09-02 09:48:25.042 DEBUG 80412 --- [io-10009-exec-5] o.a.tomcat.util.net.jsse.JSSESupport : Error trying to obtain a certificate from the client javax.net.ssl.SSLPeerUnverifiedException: peer not authenticated at java.base/sun.security.ssl.SSLSessionImpl.getPeerCertificates(SSLSessionImpl.java:556) ~[na:na] at org.apache.tomcat.util.net.jsse.JSSESupport.getPeerCertificateChain(JSSESupport.java:106) ~[tomcat-embed-core-9.0.41.jar:9.0.41]
我已经尝试了十多种CORS实现方案,包括@CrossOrigin注解和Global CORS configutation,均未达到预期效果。
当前我向Spring服务端发送Get-Request时,服务端没有处理该请求而是直接将其重定向到ADFS,由此触发报错,这是因为ADFS本身无法处理这类请求。
请问我该如何阻止Spring服务端将Get-Request重定向到ADFS?
解决方案
你遇到的问题本质不是CORS配置错误,而是Spring Security SAML的认证拦截优先级高于CORS配置,且未认证请求默认触发重定向到身份提供商的逻辑,调整Spring Security配置即可解决:
- 首先调整CORS过滤器优先级,让它在Spring Security认证过滤器之前执行,同时放开预检请求、公共接口的认证限制,修改未认证异步请求的处理逻辑,不再返回重定向而是返回401状态码:
@Override protected void configure(HttpSecurity http) throws Exception { http // 优先启用CORS,Spring会自动读取你定义的CorsConfigurationSource Bean .cors().and() .authorizeRequests() // 所有OPTIONS预检请求直接放行 .antMatchers(HttpMethod.OPTIONS, "/**").permitAll() // 把不需要走ADFS认证的接口路径加到此处,比如公共接口、健康检查接口 .antMatchers("/api/public/**", "/actuator/**").permitAll() .anyRequest().authenticated() .and() // 异步请求未认证时返回401,不触发重定向到ADFS的逻辑 .exceptionHandling() .defaultAuthenticationEntryPointFor( new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED), // 匹配前端异步请求,可根据你的业务场景调整匹配规则 new RequestHeaderRequestMatcher("X-Requested-With", "XMLHttpRequest") ) // 此处保留你原有SAML相关的配置即可 .and() .apply(samlConfigurer()); }
- 如果你要全局关闭所有未认证请求的重定向逻辑,直接替换默认的认证入口点即可:
http.exceptionHandling() .authenticationEntryPoint(new HttpStatusEntryPoint(HttpStatus.UNAUTHORIZED));
- 排查SSL日志报错:日志中的
SSLPeerUnverifiedException是因为Tomcat开启了客户端证书校验,如果你不需要双向SSL认证,可以在application配置文件中关闭:
server.ssl.client-auth=none
注意:如果你的全局CORS配置是通过实现
WebMvcConfigurer接口配置的,Spring Security默认不会读取该配置,需要单独将CorsConfigurationSource注册为Bean:
@Bean public CorsConfigurationSource corsConfigurationSource() { CorsConfiguration configuration = new CorsConfiguration(); // 替换为你的前端实际域名,不要直接写* configuration.setAllowedOrigins(Arrays.asList("https://your-frontend-domain.com")); configuration.setAllowedMethods(Arrays.asList("GET","POST","PUT","DELETE","OPTIONS")); configuration.setAllowedHeaders(Arrays.asList("*")); configuration.setAllowCredentials(true); UrlBasedCorsConfigurationSource source = new UrlBasedCorsConfigurationSource(); source.registerCorsConfiguration("/**", configuration); return source; }
内容的提问来源于stack exchange,提问作者Der Typ
相关产品推荐
相关产品推荐

