使用自定义访问决策管理器设置spring security method authentication
时,我收到一个循环bean依赖性错误,该错误会中止服务器启动。
自定义访问决策管理器使用也在应用程序中其他地方使用的服务从数据库中读取安全性参考数据,这些服务本身也是安全的:
我正在使用spring security 3.0.5
,这是主要的错误消息(请参阅下面的完整堆栈跟踪):
创建名为'securityReferenceDataService'的bean时出错:Bean 名称'securityReferenceDataService'已注入其他名称 bean [myAccessDecisionManager]在其原始版本中作为一部分 循环引用,但最终被包裹。
这是global-security-method
元素和安全性参考数据服务的弹簧配置:
<bean id="myAccessDecisionManager" class="sample.mvc.root.context.services.MyAccessDecisionManager">
<property name="securityReferenceDataService" ref="securityReferenceDataService"/>
</bean>
<security:global-method-security secured-annotations="enabled"
jsr250-annotations="enabled" access-decision-manager-ref="myAccessDecisionManager" />
这是安全参考数据服务的简化代码:
public class SecurityReferenceDataDao {
@Secured(value = "ADMIN")
public List<SecurityReferenceData> loadSecurityReferenceData() {
...
}
}
完整堆栈跟踪:
org.springframework.beans.factory.BeanCurrentlyInCreationException: Error creating bean with name 'securityReferenceDataService': Bean with name 'securityReferenceDataService' has been injected into other beans [myAccessDecisionManager] in its raw version as part of a circular reference, but has eventually been wrapped. This means that said other beans do not use the final version of the bean. This is often the result of over-eager type matching - consider using 'getBeanNamesOfType' with the 'allowEagerInit' flag turned off, for example.
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:551)
at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:461)
at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:295)
at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:223)
at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:292)
at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:194)
at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:626)
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:389)
at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:294)
at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:112)
at org.mortbay.jetty.handler.ContextHandler.startContext(ContextHandler.java:549)
at org.mortbay.jetty.servlet.Context.startContext(Context.java:136)
at org.mortbay.jetty.webapp.WebAppContext.startContext(WebAppContext.java:1282)
at org.mortbay.jetty.handler.ContextHandler.doStart(ContextHandler.java:518)
at org.mortbay.jetty.webapp.WebAppContext.doStart(WebAppContext.java:499)
at org.mortbay.jetty.plugin.Jetty6PluginWebAppContext.doStart(Jetty6PluginWebAppContext.java:115)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152)
at org.mortbay.jetty.handler.ContextHandlerCollection.doStart(ContextHandlerCollection.java:156)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerCollection.doStart(HandlerCollection.java:152)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.handler.HandlerWrapper.doStart(HandlerWrapper.java:130)
at org.mortbay.jetty.Server.doStart(Server.java:224)
at org.mortbay.component.AbstractLifeCycle.start(AbstractLifeCycle.java:50)
at org.mortbay.jetty.plugin.Jetty6PluginServer.start(Jetty6PluginServer.java:132)
at org.mortbay.jetty.plugin.AbstractJettyMojo.startJetty(AbstractJettyMojo.java:454)
at org.mortbay.jetty.plugin.AbstractJettyMojo.execute(AbstractJettyMojo.java:396)
at org.mortbay.jetty.plugin.Jetty6RunWar.execute(Jetty6RunWar.java:67)
at org.apache.maven.plugin.DefaultBuildPluginManager.executeMojo(DefaultBuildPluginManager.java:106)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:208)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:153)
at org.apache.maven.lifecycle.internal.MojoExecutor.execute(MojoExecutor.java:145)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:84)
at org.apache.maven.lifecycle.internal.LifecycleModuleBuilder.buildProject(LifecycleModuleBuilder.java:59)
at org.apache.maven.lifecycle.internal.LifecycleStarter.singleThreadedBuild(LifecycleStarter.java:183)
at org.apache.maven.lifecycle.internal.LifecycleStarter.execute(LifecycleStarter.java:161)
at org.apache.maven.DefaultMaven.doExecute(DefaultMaven.java:317)
at org.apache.maven.DefaultMaven.execute(DefaultMaven.java:152)
at org.apache.maven.cli.MavenCli.execute(MavenCli.java:555)
at org.apache.maven.cli.MavenCli.doMain(MavenCli.java:214)
at org.apache.maven.cli.MavenCli.main(MavenCli.java:158)
at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57)
at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
at java.lang.reflect.Method.invoke(Method.java:606)
at org.codehaus.plexus.classworlds.launcher.Launcher.launchEnhanced(Launcher.java:289)
at org.codehaus.plexus.classworlds.launcher.Launcher.launch(Launcher.java:229)
at org.codehaus.plexus.classworlds.launcher.Launcher.mainWithExitCode(Launcher.java:415)
at org.codehaus.plexus.classworlds.launcher.Launcher.main(Launcher.java:356)
at org.codehaus.classworlds.Launcher.main(Launcher.java:46)
答案 0 :(得分:1)
问题是自定义访问决策管理器使用的参考数据服务本身是以@Secured
保护的。
这会导致创建访问决策管理器的情况,我们需要将其包装在需要访问决策管理器的安全代理中,需要安全参考数据服务,需要将其包装在链接到访问决策经理,......等。
这种方法的工作方式是global-method-security
元素(在非aspectJ模式下)导致spring安全性注册安全顾问MethodSecurityMetadataSourceAdvisor
,该安全顾问将应用于包含至少一个{{1}的任何bean注释。
为了打破循环注入问题,解决方案是向自定义访问决策管理器传递未应用安全方面的参考数据服务的非安全版本。这有两种方法:
使用spring security run-as-manager-ref解决方案:
一种方法是使用spring security 3.1具有Run-As机制,让方法安全访问决策管理器使用给定角色而不是当前用户的角色运行,使用属性run-as-manager-ref @Secured
。
使用内部bean:
在使用最常见的编织机制(JDK或CGLIB代理)应用方面的应用程序中,这也可以通过内部bean来解决:
global-method-security
注意:如果使用加载时或编译时编织
,则无法使用