简体   繁体   English

使用Java配置和Spring Security 3.2的安全方法注释

[英]Security Method Annotations with Java Configuration and Spring Security 3.2

I am having some issues getting my application set up using method level annotation controlled by @EnableGlobalMethodSecurity I am using Servlet 3.0 style initialization using 我在使用由@EnableGlobalMethodSecurity控制的方法级别注释设置我的应用程序时遇到一些问题我正在使用Servlet 3.0样式初始化

public class SecurityWebApplicationInitializer extends AbstractSecurityWebApplicationInitializer {

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

I have attempted 2 different ways of initialising an AuthenticationManager both with their own issues. 我尝试了两种不同的方法来初始化AuthenticationManager和它们自己的问题。 Please note that not using @EnableGlobalMethodSecurity results in a successful server start up and all of the form security executes as expected. 请注意, 使用@EnableGlobalMethodSecurity导致服务器启动成功,并且所有表单安全性都按预期执行。 My issues arise when I add @EnableGlobalMethodSecurity and @PreAuthorize("hasRole('ROLE_USER')") annotations on my controller. 当我在@EnableGlobalMethodSecurity添加@EnableGlobalMethodSecurity@PreAuthorize("hasRole('ROLE_USER')")注释时,我的问题出现了。

I am attempting to set up form-based and api-based security independently. 我试图独立设置基于表单和基于api的安全性。 The method based annotations need only work for the api security. 基于注释的方法仅需要用于api安全性。

One configuration was the following. 一种配置如下。

@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");
        }
    }

}

This is not ideal as I really want only a single registration of the authentication mechanism but the main issue is that it results in the following exception: 这并不理想,因为我真的只想要一次注册认证机制,但主要问题是它会导致以下异常:

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

As far as I am aware @EnableGlobalMethodSecurity sets up its own AuthenticationManager so I'm not sure what the problem is here. 据我所知@EnableGlobalMethodSecurity设置自己的AuthenticationManager所以我不确定这里有什么问题。

The second configuration is as follows. 第二种配置如下。

@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();
        }
    }

}

This config actually starts successfully but with an exception 此配置实际上已成功启动,但有例外

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)

and when I test I found that the security doesn't work. 当我测试时,我发现安全性不起作用。

I've been looking at this for a couple of days now and even after diving into spring security implementation code I can't seem to find what is wrong with my configuration. 我已经看了几天了,甚至在深入了解Spring安全实现代码后,我似乎无法找到我的配置有什么问题。

I am using spring-security-3.2.0.RC1 and spring-framework-3.2.3.RELEASE. 我使用的是spring-security-3.2.0.RC1和spring-framework-3.2.3.RELEASE。

When you use the protected registerAuthentication methods on WebSecurityConfigurerAdapter it is scoping the Authentication to that WebSecurityConfigurerAdapter so EnableGlobalMethodSecurity cannot find it. 当您在WebSecurityConfigurerAdapter上使用protected registerAuthentication方法时,它会将身份验证范围限定为该WebSecurityConfigurerAdapter因此EnableGlobalMethodSecurity无法找到它。 If you think about this...it makes sense since the method is protected. 如果你考虑这个...它是有道理的,因为该方法是受保护的。

The error you are seeing is actually a debug statement (note the level is DEBUG). 您看到的错误实际上是一个调试语句(注意级别是DEBUG)。 The reason is that Spring Security will try a few different ways to automatically wire the Global Method Security. 原因是Spring Security将尝试使用几种不同的方法来自动连接全局方法安全性。 Specifically EnableGlobalMethodSecurity will try the following ways to try and get the AuthenticationManager : 具体来说, EnableGlobalMethodSecurity将尝试以下方式来尝试获取AuthenticationManager

  • If you extend GlobalMethodSecurityConfiguration and override the registerAuthentication it will use the AuthenticationManagerBuilder that was passed in. This allows for isolating the AuthenticationManager in the same way you can do so with WebSecurityConfigurerAdapter 如果扩展GlobalMethodSecurityConfiguration并覆盖registerAuthentication ,它将使用传入的AuthenticationManagerBuilder 。这允许以与使用WebSecurityConfigurerAdapter相同的方式隔离AuthenticationManager
  • Try to build from the global shared instance of AuthenticationManagerBuilder , if it fails it logs the error message you are seeing (Note the logs also state "This is ok for now, we will try using an AuthenticationManager directly") 尝试从AuthenticationManagerBuilder的全局共享实例构建,如果失败则记录您看到的错误消息(注意日志还说明“现在可以,我们将尝试直接使用AuthenticationManager”)
  • Try to use an AuthenticationManager that is exposed as a bean. 尝试使用作为bean公开的AuthenticationManager

For your code, you are going to be best off using something like the following: 对于您的代码,您最好使用以下内容:

@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();
        }
    }

}

NOTE: More documentation around this will be getting added to the reference in the coming days. 注意:有关此内容的更多文档将在未来几天内添加到参考中。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM