【问题标题】:How to enable secured-annotations with Java based configuration?如何使用基于 Java 的配置启用安全注释?
【发布时间】:2014-09-11 23:41:47
【问题描述】:

我想为我的控制器操作使用@Secured 注释。由于我有基于 java 的配置,我需要知道如何设置

<security:global-method-security secured-annotations="enabled" />

不带 xml 文件的选项。

更新 1:

我将@EnableGlobalMethodSecurity(securedEnabled = true) 添加到我的安全配置类中:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(securedEnabled = true)
public class LIRSecurityConfig extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
            .authenticationProvider(preAuthenticatedAuthenticationProvider())
            .addFilter(cookiePreAuthenticationFilter())
            .authorizeRequests()
            .antMatchers("/**")
            .hasAnyAuthority("ROLE_USER")
            ;
    }

    ...
}

在启动时会导致此异常

Jul 21, 2014 3:32:54 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class org.springframework.web.context.ContextLoaderListener
org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'methodSecurityInterceptor' defined in class path resource [org/springframework/security/config/annotation/method/configuration/GlobalMethodSecurityConfiguration.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: An AuthenticationManager is required
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1512)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:521)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:458)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:296)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:293)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:633)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:932)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:479)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:410)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:306)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4937)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5434)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1559)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1549)
    at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:303)
    at java.util.concurrent.FutureTask.run(FutureTask.java:138)
    at java.util.concurrent.ThreadPoolExecutor$Worker.runTask(ThreadPoolExecutor.java:895)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:918)
    at java.lang.Thread.run(Thread.java:695)
Caused by: java.lang.IllegalArgumentException: An AuthenticationManager is required
    at org.springframework.util.Assert.notNull(Assert.java:112)
    at org.springframework.security.access.intercept.AbstractSecurityInterceptor.afterPropertiesSet(AbstractSecurityInterceptor.java:121)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1571)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1509)
    ... 22 more
Jul 21, 2014 3:32:54 PM org.apache.catalina.core.StandardContext

更新 2:

添加后

@Bean
@Override
public AuthenticationManager authenticationManagerBean() throws Exception {
    return super.authenticationManagerBean();
}

我得到另一个例外:

Caused by: org.springframework.beans.FatalBeanException: A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication.
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.validateBeanCycle(WebSecurityConfigurerAdapter.java:462)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter$AuthenticationManagerDelegator.<init>(WebSecurityConfigurerAdapter.java:430)
    at org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter.authenticationManagerBean(WebSecurityConfigurerAdapter.java:220)
    at com.galexis.lir.config.LIRSecurityConfig.authenticationManagerBean(LIRSecurityConfig.java:36)
    at com.galexis.lir.config.LIRSecurityConfig$$EnhancerBySpringCGLIB$$88306f96.CGLIB$authenticationManagerBean$3(<generated>)
    at com.galexis.lir.config.LIRSecurityConfig$$EnhancerBySpringCGLIB$$88306f96$$FastClassBySpringCGLIB$$a4d1ea33.invoke(<generated>)
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228)
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:293)
    at com.galexis.lir.config.LIRSecurityConfig$$EnhancerBySpringCGLIB$$88306f96.authenticationManagerBean(<generated>)
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:39)
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:25)
    at java.lang.reflect.Method.invoke(Method.java:597)
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:160)
    ... 77 more

【问题讨论】:

  • LIRSecurityConfig 的其余部分是什么样的?

标签: java spring spring-security


【解决方案1】:

你需要使用

@EnableGlobalMethodSecurity(securedEnabled = true)

注解,在docs中定义。

【讨论】:

    【解决方案2】:

    您还应该为 Manager 添加一个 bean。看看这个:

    @Configuration
    @EnableWebMvcSecurity
    @EnableGlobalMethodSecurity(securedEnabled = true)
    public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
    
        @Resource(name = "authService")
        private UserDetailsService userDetailsService;
    
        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    
        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            Md5PasswordEncoder encoder = new Md5PasswordEncoder();
            auth.userDetailsService(userDetailsService).passwordEncoder(encoder);
        }
    
        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .formLogin()
                .loginPage("/login")
                .and()
                .logout()
                .logoutSuccessUrl("/");
        }
    }
    

    重要的是

        @Bean
        @Override
        public AuthenticationManager authenticationManagerBean() throws Exception {
            return super.authenticationManagerBean();
        }
    

    【讨论】:

    • 我也是这么想的,不幸的是,这会产生FatalBeanException: A dependency cycle was detected when trying to resolve the AuthenticationManager. Please ensure you have configured authentication.(参见上面的更新2)。
    • 你永远不应该使用 MD5 作为密码哈希。使用 BCryptPasswordEncoder
    • 声明一个返回一个已经定义的bean有什么意义? Bean Override public AuthenticationManager authenticationManagerBean() throws Exception { return super.authenticationManagerBean(); }
    • @Adelin 将该对象声明为 Bean,否则不会被选中。
    • 我花了 2 天时间才找到并使用这个解决方案。对于我的(复杂)配置,AbstractSecurityInterceptor 中的 authenticationManager 为空,但未添加 authenticationManagerBean
    【解决方案3】:

    仅适用于其他将尝试解决“尝试解析 AuthenticationManager 时检测到依赖循环。请确保您已配置身份验证。”问题。

    解决方法是添加以下方法:

    @Override
    @Autowired
    public void configure(AuthenticationManagerBuilder auth) throws Exception {
        // do NOT call super.configure() !
        ...
    }
    

    【讨论】:

      【解决方案4】:

      这样就成功了:

      @Configuration
      @EnableWebSecurity
      @EnableGlobalMethodSecurity(prePostEnabled = true)
      public class SecurityConfiguration extends WebSecurityConfigurerAdapter {
      
          @Bean
          @Override
          public AuthenticationManager authenticationManagerBean() throws Exception {
              return super.authenticationManagerBean();
          }
      
          @Autowired
          public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
              auth.inMemoryAuthentication().
                      withUser("user").password("user").roles("USER").and().
                      withUser("admin").password("admin").roles("USER", "ADMIN");
          }
      
          @Override
          protected void configure(HttpSecurity http) throws Exception {
              http
                      .authorizeRequests()
                      .anyRequest().authenticated()
                      .and()
                      .httpBasic();
          }
      
          @Override
          public void configure(WebSecurity web) throws Exception {
              super.configure(web);
          }
      }
      

      重要的部分是

          @Bean
          @Override
          public AuthenticationManager authenticationManagerBean() throws Exception {
              return super.authenticationManagerBean();
          }
      
          @Autowired
          public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
              auth.inMemoryAuthentication().
                      withUser("user").password("user").roles("USER").and().
                      withUser("admin").password("admin").roles("USER", "ADMIN");
          }
      

      【讨论】:

      • AuthenticationManager 添加@Bean 为我做到了。我没有configureGlobal() 方法,尽管我确实有一个用于 AuthenticationManagerBuilder 的配置方法,其中包含一个 UserDetailsS​​ervice。
      【解决方案5】:

      Stefan 是对的,添加了

      @EnableGlobalMethodSecurity(securedEnabled = true)
      

      成功了。

      在我的特殊情况下,我必须添加以摆脱 excptions。

      @Autowired
      public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
          auth
              .inMemoryAuthentication()
                  .withUser("user").password("password").authorities("ROLE_USER");
      }
      

      【讨论】:

        【解决方案6】:

        关注注释中的类

         @Configuration
            @EnableGlobalMethodSecurity(securedEnabled = true)
            public class SecurityConfigProvider extends GlobalMethodSecurityConfiguration {
        
                @Override
                protected MethodSecurityExpressionHandler createExpressionHandler() {
                    return new OAuth2MethodSecurityExpressionHandler();
                }
        
            }
        
        
        @Configuration
        @EnableOAuth2Client
        @EnableWebSecurity
        public class OAuth2SecurityConfiguration extends WebSecurityConfigurerAdapter {
        
            @Autowired
            OAuth2ClientContext oauth2ClientContext;
        
            @Override
            protected void configure(HttpSecurity http) throws Exception {
                //TODO
            }
        
            @Override
            public void configure(WebSecurity web) throws Exception {
                //TODO
            }
        
            @Override
            @Bean
            public AuthenticationManager authenticationManagerBean() throws Exception {
                return super.authenticationManagerBean();
            }
        
        }
        

        【讨论】:

          【解决方案7】:

          导入 org.springframework.security.config.annotation.method.configuration.EnableGlobalMethodSecurity;

          @EnableGlobalMethodSecurity(prePostEnabled=true)

          【讨论】:

            猜你喜欢
            • 2018-02-13
            • 2014-08-21
            • 2017-05-27
            • 2013-10-21
            • 2016-08-01
            • 2017-05-30
            • 2016-08-02
            • 2013-03-23
            相关资源
            最近更新 更多