You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.08.05 09:25:20