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
相关产品推荐
相关产品推荐

