具有多个提供程序的 Spring 安全性

时间:2021-03-03 01:38:26

标签: java spring-security cas

我正在为 2 个不同的用户设置一个应用:

  • 我的 ldap 中的一个,可以连接 cas 身份验证
  • 一个外部硬编码,使用简单的登录表单

我创建了 2 个安全配置:

外部用户配置:

@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
@Order(1)
public class SecurityVanuatuConfiguration extends WebSecurityConfigurerAdapter {

@Bean
@Override
public UserDetailsService userDetailsService() {
    UserDetails user =
        User.withUsername("user")
            .password("{noop}user")
            .roles("USER")
            .build();

    return new InMemoryUserDetailsManager(user);
}

@Override
protected void configure(HttpSecurity http) throws Exception {
    http
        .csrf().disable().antMatcher("/user/**")
        .authorizeRequests()
        .requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
        .anyRequest().authenticated()
        .and()
        .formLogin()
        .loginPage(LOGIN_URL).permitAll()
        .loginProcessingUrl(LOGIN_PROCESSING_URL)
        .failureUrl(LOGIN_FAILURE_URL)
        .successHandler(successHandler)
        .failureHandler(successHandler)
        .and().logout().logoutSuccessUrl(LOGOUT_SUCCESS_URL);
}

Cas 配置:

@EnableWebSecurity
@Configuration
@RequiredArgsConstructor
@Order(2)
public class SecurityCasConfiguration extends WebSecurityConfigurerAdapter {

@Override
protected void configure(HttpSecurity http) throws Exception {
    http.csrf().disable().antMatcher("/admin/**")
        .authorizeRequests()
        .requestMatchers(SecurityUtils::isFrameworkInternalRequest).permitAll()
        .anyRequest().authenticated()
        .and()
        .httpBasic()
        .authenticationEntryPoint(authenticationEntryPoint())
        .and()
        .addFilter(casAuthenticationFilter())
        .addFilterBefore(casLogoutFilter(), CasAuthenticationFilter.class);
}

@Bean
public SingleSignOutFilter casLogoutFilter() {
    SingleSignOutFilter singleSignOutFilter = new SingleSignOutFilter();
    return singleSignOutFilter;
}

// if I remove this bean, external configuration works
@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
    CasAuthenticationProvider provider = new CasAuthenticationProvider();
    provider.setServiceProperties(serviceProperties());
    provider.setTicketValidator(new Cas30ServiceTicketValidator("https://sso.unc.nc/cas"));
    provider.setKey("cas");
    provider.setAuthenticationUserDetailsService(successHandler);
    return provider;
}

每个配置单独工作时,但当两者都存在时,外部不起作用。

似乎 CasAuthenticationProvider bean 阻止了 formLogin 的工作,而我最终进入了 FailureHandler。

这里是错误:

org.springframework.security.authentication.ProviderNotFoundException: No AuthenticationProvider found for org.springframework.security.authentication.UsernamePasswordAuthenticationToken

我怎样才能让这两个配置一起工作?

1 个答案:

答案 0 :(得分:1)

当您将某些内容标记为 @Bean 时,您就是将其放入 bean 池中,如果需要,spring 可以使用该池注入类。

您已注册

@Bean
public CasAuthenticationProvider casAuthenticationProvider() {
    ...
}

作为 @Bean 是一个 AuthenticationProvider。当您使用 @Bean 注册它时,每个需要它的人都会收到它,这意味着您的 WebSecurityConfigurerAdapter 都会使用它。

Spring 无法知道您只希望这是在您的一个安全配置中,而不是另一个。

您必须通过删除 @Bean 并手动设置它来明确定义您希望它在一个中而不是另一个中。

@Override
protected void configure(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(casAuthenticationProvider());
}

public CasAuthenticationProvider casAuthenticationProvider() {
    ...
}

如果你想手动设置一些东西,你必须总是决定,或者使用 @Bean 并让 spring 为你注入它。

因此,例如,您正在注册一个过滤器 (casLogoutFilter) 手动设置它,但也将其定义为 @Bean 告诉 spring 将其注入过滤器链,这有点没有意义。

相关问题