如何使用基于 Java 的配置启用安全注释?
Posted
技术标签:
【中文标题】如何使用基于 Java 的配置启用安全注释?【英文标题】:How to enable secured-annotations with Java based configuration? 【发布时间】: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
的其余部分是什么样的?
【参考方案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 的配置方法,其中包含一个 UserDetailsService。【参考方案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)
【讨论】:
以上是关于如何使用基于 Java 的配置启用安全注释?的主要内容,如果未能解决你的问题,请参考以下文章
如何在类级别注释中为 JavaDocs 启用 Java checkstyle?