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

Spring Security自定义OIDC User Service无法被调用的问题排查

问题本质与解决方案

你对问题的分析完全正确:在Spring Security 5.8.5的默认配置中,OAuth2LoginAuthenticationProvider的注册顺序早于OidcAuthorizationCodeAuthenticationProvider,而两者都支持OAuth2LoginAuthenticationToken,导致普通OAuth2登录的提供者先处理请求,OIDC专属的认证流程(包括你的自定义OidcUserService)根本没有执行机会。

解决方案1:手动调整AuthenticationProvider顺序

直接自定义ProviderManager,将OidcAuthorizationCodeAuthenticationProvider放在首位,确保OIDC请求优先进入对应流程:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final ClientRegistrationRepository clientRegistrationRepository;
    private final MyCustomOidcUserService myCustomOidcUserService;

    public SecurityConfig(ClientRegistrationRepository clientRegistrationRepository,
                         MyCustomOidcUserService myCustomOidcUserService) {
        this.clientRegistrationRepository = clientRegistrationRepository;
        this.myCustomOidcUserService = myCustomOidcUserService;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Login(oauth2 -> oauth2
                .userInfoEndpoint(userInfo -> userInfo.oidcUserService(myCustomOidcUserService))
                .authenticationManager(authenticationManager())
            );
    }

    @Override
    protected AuthenticationManager authenticationManager() throws Exception {
        // 初始化OIDC认证提供者,绑定自定义UserService
        OidcAuthorizationCodeAuthenticationProvider oidcProvider = 
            new OidcAuthorizationCodeAuthenticationProvider(
                new DefaultAuthorizationCodeTokenResponseClient(),
                new DefaultOidcUserService(myCustomOidcUserService),
                clientRegistrationRepository
            );

        // 初始化普通OAuth2登录提供者
        OAuth2LoginAuthenticationProvider oauth2Provider = 
            new OAuth2LoginAuthenticationProvider(
                new DefaultAuthorizationCodeTokenResponseClient(),
                new DefaultOAuth2UserService(),
                clientRegistrationRepository
            );

        // 按优先级排序,OIDC提供者在前
        return new ProviderManager(Arrays.asList(oidcProvider, oauth2Provider));
    }
}

解决方案2:通过OAuth2LoginConfigurer自定义提供者集合

在OAuth2登录配置中,替换默认的提供者解析逻辑,手动指定顺序:

@Configuration
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    private final ClientRegistrationRepository clientRegistrationRepository;
    private final MyCustomOidcUserService myCustomOidcUserService;

    public SecurityConfig(ClientRegistrationRepository clientRegistrationRepository,
                         MyCustomOidcUserService myCustomOidcUserService) {
        this.clientRegistrationRepository = clientRegistrationRepository;
        this.myCustomOidcUserService = myCustomOidcUserService;
    }

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .oauth2Login(oauth2 -> {
                oauth2.userInfoEndpoint(userInfo -> userInfo.oidcUserService(myCustomOidcUserService));
                
                // 覆盖默认的提供者解析器,按指定顺序返回提供者
                oauth2.authenticationProviderResolver(request -> {
                    OidcAuthorizationCodeAuthenticationProvider oidcProvider = 
                        new OidcAuthorizationCodeAuthenticationProvider(
                            new DefaultAuthorizationCodeTokenResponseClient(),
                            new DefaultOidcUserService(myCustomOidcUserService),
                            clientRegistrationRepository
                        );

                    OAuth2LoginAuthenticationProvider oauth2Provider = 
                        new OAuth2LoginAuthenticationProvider(
                            new DefaultAuthorizationCodeTokenResponseClient(),
                            new DefaultOAuth2UserService(),
                            clientRegistrationRepository
                        );

                    return Arrays.asList(oidcProvider, oauth2Provider);
                });
            });
    }
}

注意事项

无Spring Boot环境下,需手动注册ClientRegistrationRepositoryBean,示例如下:

@Bean
public ClientRegistrationRepository clientRegistrationRepository() {
    return new InMemoryClientRegistrationRepository(buildOidcClientRegistration());
}

private ClientRegistration buildOidcClientRegistration() {
    return ClientRegistration.withRegistrationId("your-oidc-provider")
        .clientId("client-id")
        .clientSecret("client-secret")
        .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE)
        .redirectUri("{baseUrl}/login/oauth2/code/your-oidc-provider")
        .scope("openid", "profile", "email")
        .authorizationUri("https://your-oidc-server.com/oauth2/auth")
        .tokenUri("https://your-oidc-server.com/oauth2/token")
        .userInfoUri("https://your-oidc-server.com/oauth2/userinfo")
        .jwkSetUri("https://your-oidc-server.com/oauth2/jwks")
        .clientName("Your OIDC Provider")
        .build();
}

内容的提问来源于stack exchange,提问作者dtrunk

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.12 02:58:12