12

@EnableGlobalMethodSecurity我在使用由我使用 Servlet 3.0 样式初始化控制的方法级别注释来设置我的应用程序时遇到一些问题

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

    public SecurityWebApplicationInitializer() {
        super(MultiSecurityConfig.class);
    }
}

我尝试了两种不同的方法来初始化AuthenticationManager两者都有自己的问题。请注意,使用@EnableGlobalMethodSecurity会导致服务器成功启动,并且所有表单安全性都按预期执行。@EnableGlobalMethodSecurity当我在控制器上添加和@PreAuthorize("hasRole('ROLE_USER')")注释时,我的问题就出现了。

我正在尝试独立设置基于表单和基于 api 的安全性。基于方法的注释只需要为 api 安全工作。

一种配置如下。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MultiSecurityConfig {

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/api/**").httpBasic();
        }

        protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                .withUser("user").password("password").roles("USER").and()
                .withUser("admin").password("password").roles("USER", "ADMIN");
        }
    }

    @Configuration
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/static/**","/status");
        }

        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().hasRole("USER").and()
                .formLogin().loginPage("/login").permitAll();
        }

        protected void registerAuthentication(AuthenticationManagerBuilder auth) throws Exception {
            auth.inMemoryAuthentication()
                .withUser("user").password("password").roles("USER").and()
                .withUser("admin").password("password").roles("USER", "ADMIN");
        }
    }

}

这并不理想,因为我真的只想要身份验证机制的单一注册,但主要问题是它会导致以下异常:

java.lang.IllegalArgumentException: Expecting to only find a single bean for type interface org.springframework.security.authentication.AuthenticationManager, but found []

据我所知@EnableGlobalMethodSecurity,设置了自己的AuthenticationManager,所以我不确定这里的问题是什么。

第二种配置如下。

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MultiSecurityConfig {

    @Bean
    protected AuthenticationManager authenticationManager() throws Exception {
        return new AuthenticationManagerBuilder(ObjectPostProcessor.QUIESCENT_POSTPROCESSOR)
                .inMemoryAuthentication()
                    .withUser("user").password("password").roles("USER").and()
                    .withUser("admin").password("password").roles("USER", "ADMIN").and()
                    .and()
                .build();
    }

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        @Override protected void configure(HttpSecurity http) throws Exception {
            http.antMatcher("/api/**").httpBasic();
        }
    }

    @Configuration
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/static/**","/status");
        }

        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().anyRequest().hasRole("USER").and()
                .formLogin().loginPage("/login").permitAll();
        }
    }

}

此配置实际上已成功启动,但有异常

java.lang.IllegalArgumentException: A parent AuthenticationManager or a list of AuthenticationProviders is required
at org.springframework.security.authentication.ProviderManager.checkState(ProviderManager.java:117)
at org.springframework.security.authentication.ProviderManager.<init>(ProviderManager.java:106)
at org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder.performBuild(AuthenticationManagerBuilder.java:221)

当我测试时,我发现安全性不起作用。

我已经看了几天了,即使在深入研究 spring 安全实现代码之后,我似乎也找不到我的配置有什么问题。

我正在使用 spring-security-3.2.0.RC1 和 spring-framework-3.2.3.RELEASE。

4

1 回答 1

13

当您使用其上的protected registerAuthentication方法时,WebSecurityConfigurerAdapter将身份验证范围限定为无法找到它。如果您考虑一下...这是有道理的,因为该方法受到保护。WebSecurityConfigurerAdapterEnableGlobalMethodSecurity

您看到的错误实际上是一个调试语句(注意级别是 DEBUG)。原因是 Spring Security 会尝试几种不同的方式来自动连接 Global Method Security。具体EnableGlobalMethodSecurity会尝试以下方法来尝试获取AuthenticationManager

  • 如果您扩展GlobalMethodSecurityConfiguration并覆盖registerAuthentication它,它将使用AuthenticationManagerBuilder传入的。这允许以AuthenticationManager与您可以这样做相同的方式隔离WebSecurityConfigurerAdapter
  • 尝试从 的全局共享实例构建AuthenticationManagerBuilder,如果失败,它会记录您所看到的错误消息(注意日志还指出“现在还可以,我们将尝试直接使用 AuthenticationManager”)
  • 尝试使用AuthenticationManager作为 bean 公开的 。

对于您的代码,您最好使用以下内容:

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled=true)
public class MultiSecurityConfig {
    // Since MultiSecurityConfig does not extend GlobalMethodSecurityConfiguration and
    // define an AuthenticationManager, it will try using the globally defined
    // AuthenticationManagerBuilder to create one

    // The @Enable*Security annotations create a global AuthenticationManagerBuilder 
    // that can optionally be used for creating an AuthenticationManager that is shared
    // The key to using it is to use the @Autowired annotation
    @Autowired
    public void registerSharedAuthentication(AuthenticationManagerBuilder auth) throws Exception {
        auth
            .inMemoryAuthentication()
                .withUser("user").password("password").roles("USER").and()
                .withUser("admin").password("password").roles("USER", "ADMIN");
    }

    @Configuration
    @Order(1)
    public static class ApiWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
        // Since we didn't specify an AuthenticationManager for this class,
        // the global instance is used


        protected void configure(HttpSecurity http) throws Exception {
            http
                .antMatcher("/api/**")
                .httpBasic();
        }
    }

    @Configuration
    public static class FormWebSecurityConfigurerAdapter extends WebSecurityConfigurerAdapter {
        // Since we didn't specify an AuthenticationManager for this class,
        // the global instance is used

        public void configure(WebSecurity web) throws Exception {
            web
                .ignoring()
                    .antMatchers("/static/**","/status");
        }

        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .anyRequest().hasRole("USER")
                    .and()
                .formLogin()
                    .loginPage("/login")
                    .permitAll();
        }
    }

}

注意:在接下来的几天里,更多关于此的文档将被添加到参考中。

于 2013-10-14T19:30:35.000 回答