如何在Spring Boot应用中集成双Spring Security认证并支持切换
解决方案:实现两种认证方式的配置切换与共存
错误原因分析
你遇到的IllegalStateException是因为Spring Security不允许同时使用旧版的WebSecurityConfigurerAdapter配置方式和新版的SecurityFilterChain配置方式。Azure AD的starter在Spring Boot 2.7.x版本中默认会自动注册一个WebSecurityConfigurerAdapter实例,而你自己的Documentum认证使用了SecurityFilterChain,两者冲突导致启动失败。
具体实现步骤
1. 整合所有依赖
保留两种认证所需的Maven依赖,注意Azure AD starter版本要与Spring Boot 2.7.3匹配(推荐4.4.0):
<!-- Documentum 认证依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-security</artifactId> <version>2.7.3</version> </dependency> <!-- Azure AD SSO 依赖 --> <dependency> <groupId>org.springframework.boot</groupId> <artifactId>spring-boot-starter-oauth2-client</artifactId> <version>2.7.3</version> </dependency> <dependency> <groupId>com.azure.spring</groupId> <artifactId>spring-cloud-azure-starter-active-directory</artifactId> <version>4.4.0</version> </dependency>
2. 添加配置开关
在application.properties中新增认证类型开关,同时保留原有配置:
# 认证类型开关:可选值 documentum / azure-ad,默认启用documentum auth.type=documentum # Documentum 相关配置(按需补充) # documentum.repo-url=xxx # Azure AD 配置 spring.cloud.azure.active-directory.enabled=false spring.cloud.azure.active-directory.profile.tenant-id=xxxxxxxxxxxx spring.cloud.azure.active-directory.credential.client-id=yyyyyyyyyyyy spring.cloud.azure.active-directory.credential.client-secret=zzzzzzzzzz
3. 禁用Azure AD的自动配置
在应用启动类中排除Azure AD自动注册的WebSecurityConfigurerAdapter,避免冲突:
@SpringBootApplication(exclude = { AadWebSecurityConfigurerAdapterAutoConfiguration.class }) public class YourApplication { public static void main(String[] args) { SpringApplication.run(YourApplication.class, args); } }
4. 拆分两种认证的配置类
用@ConditionalOnProperty注解实现配置的条件加载,确保同一时间只有一种认证方式生效。
Documentum认证配置类
@Configuration @EnableWebSecurity @ConditionalOnProperty(name = "auth.type", havingValue = "documentum", matchIfMissing = true) public class DocumentumSecurityConfig { @Bean public AuthenticationProvider authenticationProvider() { return new DocumentumAuthenticationProvider(); } @Bean public SecurityFilterChain documentumSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .formLogin() .loginPage("/content/login") .permitAll() .and() .logout() .logoutUrl("/content/logout") .logoutSuccessUrl("/content/logout") .permitAll(); return http.build(); } @Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring().antMatchers("/content/css/**" ,"/content/js/**" ,"/content/images/**" ,"/error/**"); } @Bean public BCryptPasswordEncoder encodePWD() { return new BCryptPasswordEncoder(); } }
Azure AD认证配置类
用新版SecurityFilterChain实现Azure AD的SSO配置,替代自动生成的WebSecurityConfigurerAdapter:
@Configuration @EnableWebSecurity @ConditionalOnProperty(name = "auth.type", havingValue = "azure-ad") public class AzureAdSecurityConfig { private final AadOAuth2ClientProperties aadProps; public AzureAdSecurityConfig(AadOAuth2ClientProperties aadProps) { this.aadProps = aadProps; } @Bean public SecurityFilterChain azureAdSecurityFilterChain(HttpSecurity http) throws Exception { http .authorizeRequests() .anyRequest().authenticated() .and() .oauth2Login(oauth2 -> oauth2 .clientRegistrationRepository(clientRegistrationRepository()) .authorizedClientService(authorizedClientService()) ) .logout(logout -> logout .logoutSuccessUrl("/") .permitAll() ); return http.build(); } @Bean public ClientRegistrationRepository clientRegistrationRepository() { return new InMemoryClientRegistrationRepository(azureAdClientRegistration()); } @Bean public OAuth2AuthorizedClientService authorizedClientService(ClientRegistrationRepository repo) { return new InMemoryOAuth2AuthorizedClientService(repo); } private ClientRegistration azureAdClientRegistration() { String tenantId = aadProps.getProfile().getTenantId(); return ClientRegistration.withRegistrationId("azure-ad") .clientId(aadProps.getCredential().getClientId()) .clientSecret(aadProps.getCredential().getClientSecret()) .scope("openid", "profile", "email") .authorizationUri("https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/authorize") .tokenUri("https://login.microsoftonline.com/" + tenantId + "/oauth2/v2.0/token") .userInfoUri("https://graph.microsoft.com/oidc/userinfo") .userNameAttributeName(IdTokenClaimNames.SUB) .clientName("Azure AD") .authorizationGrantType(AuthorizationGrantType.AUTHORIZATION_CODE) .redirectUri("{baseUrl}/login/oauth2/code/{registrationId}") .build(); } @Bean public WebSecurityCustomizer webSecurityCustomizer() { return (web) -> web.ignoring().antMatchers("/content/css/**" ,"/content/js/**" ,"/content/images/**" ,"/error/**"); } }
切换认证方式
只需修改application.properties中的auth.type值:
- 设置为
documentum(或留空):启用自定义Documentum表单认证 - 设置为
azure-ad:启用Azure AD单点登录
修改后重启应用即可生效。
内容的提问来源于stack exchange,提问作者Jon H
相关产品推荐
相关产品推荐

