Spring Security整合自定义认证服务器与Microsoft SSO出现重复nonce参数问题
解决Spring Boot OAuth2客户端重复nonce参数导致的AADSTS9000411错误
问题根源
你配置了openid scope后,Spring Security OAuth2的OIDC模块会自动在授权请求中添加nonce参数,但你的自定义认证服务器转发请求到微软AD时,又额外添加了一次nonce,最终因参数重复触发报错。
解决方案
1. 禁用Spring自动生成nonce
创建自定义的OAuth2AuthorizationRequestResolver,覆盖默认逻辑,移除Spring自动添加的nonce参数:
import org.springframework.security.oauth2.client.registration.ClientRegistration; import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.core.endpoint.OAuth2AuthorizationRequest; import javax.servlet.http.HttpServletRequest; import java.util.HashMap; import java.util.Map; public class CustomAuthorizationRequestResolver implements OAuth2AuthorizationRequestResolver { private final OAuth2AuthorizationRequestResolver delegate; public CustomAuthorizationRequestResolver(OAuth2AuthorizationRequestResolver delegate) { this.delegate = delegate; } @Override public OAuth2AuthorizationRequest resolve(HttpServletRequest request) { OAuth2AuthorizationRequest authorizationRequest = this.delegate.resolve(request); return customizeAuthorizationRequest(authorizationRequest); } @Override public OAuth2AuthorizationRequest resolve(HttpServletRequest request, String clientRegistrationId) { OAuth2AuthorizationRequest authorizationRequest = this.delegate.resolve(request, clientRegistrationId); return customizeAuthorizationRequest(authorizationRequest); } private OAuth2AuthorizationRequest customizeAuthorizationRequest(OAuth2AuthorizationRequest authorizationRequest) { if (authorizationRequest == null) { return null; } // 移除Spring自动添加的nonce参数 Map<String, Object> additionalParameters = new HashMap<>(authorizationRequest.getAdditionalParameters()); additionalParameters.remove("nonce"); return OAuth2AuthorizationRequest.from(authorizationRequest) .additionalParameters(additionalParameters) .build(); } }
然后在Security配置类中注册这个Resolver:
import org.springframework.context.annotation.Bean; import org.springframework.context.annotation.Configuration; import org.springframework.security.config.annotation.web.builders.HttpSecurity; import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity; import org.springframework.security.oauth2.client.registration.ClientRegistrationRepository; import org.springframework.security.oauth2.client.web.OAuth2AuthorizationRequestResolver; import org.springframework.security.oauth2.client.web.DefaultOAuth2AuthorizationRequestResolver; import org.springframework.security.web.SecurityFilterChain; @Configuration @EnableWebSecurity public class SecurityConfig { @Bean public SecurityFilterChain securityFilterChain(HttpSecurity http) throws Exception { http .authorizeHttpRequests(auth -> auth .anyRequest().authenticated() ) .oauth2Login(oauth2 -> oauth2 .authorizationEndpoint(endpoint -> endpoint .authorizationRequestResolver(customAuthorizationRequestResolver(http.getSharedObject(ClientRegistrationRepository.class))) ) ); return http.build(); } private OAuth2AuthorizationRequestResolver customAuthorizationRequestResolver(ClientRegistrationRepository clientRegistrationRepository) { DefaultOAuth2AuthorizationRequestResolver resolver = new DefaultOAuth2AuthorizationRequestResolver( clientRegistrationRepository, "/oauth2/authorization"); return new CustomAuthorizationRequestResolver(resolver); } }
2. 修正redirect-uri配置
把application.properties中的redirect-uri改成标准回调路径,不要用根路径:
spring.security.oauth2.client.registration.custom.redirect-uri=http://localhost:8080/login/oauth2/code/custom
根路径的回调会导致Spring无法正确处理授权响应,即使手动删除nonce也会触发后续异常,标准路径能保障回调流程正常执行。
3. 可选:移除openid scope(如果业务允许)
如果自定义认证服务器不需要OIDC的openid scope,直接删除该配置:
spring.security.oauth2.client.registration.custom.scope= # 留空或替换为服务器要求的其他scope
这样Spring不会触发OIDC相关的nonce生成逻辑,从根源避免参数重复问题。
内容的提问来源于stack exchange,提问作者Maxi Moser
相关产品推荐
相关产品推荐

