spring - 再次... Spring Boot/security 的方法安全性 : Error creating bean with name 'methodSecurityInterceptor' "This object has already been built"

标签 spring spring-security autowired spring-boot

我想实现方法安全性。

我遇到了 @Secured 和 @PreAuth 注释的问题。每当我将其中任何一个添加到我的服务接口(interface)时,我都会收到如下异常。没有它们,我的应用程序运行得很好。

Caused by: 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]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built

这是一个 REST 服务应用程序。

这是我的配置的一些相关部分。如果我需要添加其他内容,请告诉我。

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig {
...

    @Autowired
    private DatabaseAuthenticationProvider databaseAuthenticationProvider;
...
    @Configuration
    @Order(1)                                                        
    public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {
...
        @Override
        protected void configure(HttpSecurity http) throws Exception {
...
            http
                .authorizeRequests()
                    .antMatchers(HttpMethod.GET, "/usuario/*/rfc/*").authenticated()
                    .antMatchers(HttpMethod.GET, "/usuario/*/rfc/*/").authenticated()
                    .antMatchers(HttpMethod.GET, "/usuario/*").authenticated()
                    .antMatchers(HttpMethod.GET, "/usuario/*/").authenticated()
...          
        }
    }

    @SuppressWarnings("unchecked")
    @Bean
    public AuthenticationManager authenticationManager() throws Exception {
        return new AuthenticationManagerBuilder(new NopPostProcessor()).authenticationProvider(databaseAuthenticationProvider).build();
    }

    @SuppressWarnings("rawtypes")
    private static class NopPostProcessor implements ObjectPostProcessor {
        @Override
        public Object postProcess(Object object) {
            return object;
        }
    };

    @Bean
    public MessageDigestPasswordEncoder messageDigestPasswordEncoder() {
        return new MessageDigestPasswordEncoder("sha-256");
    }
}

还有:

@Service("databaseAuthenticationProvider")
public class DatabaseAuthenticationProvider
    extends AbstractUserDetailsAuthenticationProvider {

    private final Logger logger = LoggerFactory.getLogger(getClass());

    @Autowired
    private MessageDigestPasswordEncoder messageDigestPasswordEncoder;
...
    @Override
    protected void additionalAuthenticationChecks(UserDetails arg0,
        UsernamePasswordAuthenticationToken arg1)
        throws AuthenticationException {
        return;
    }
    @Override
    protected UserDetails retrieveUser(String username,
        UsernamePasswordAuthenticationToken authentication)
        throws AuthenticationException {
//        logger.debug("Inside retrieveUser");
        String password = (String) authentication.getCredentials();

        String encryptedPassword = "";

        if (StringUtils.hasText(password)) {
            encryptedPassword = messageDigestPasswordEncoder.encodePassword(password, null);
        }

        //UserDetails user = null;
        String expectedPassword = null;
        List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();

        WebAuthenticationDetails wad = null;
        wad = (WebAuthenticationDetails) authentication.getDetails();
...
        return new org.springframework.security.core.userdetails.User(
            username,
            password, 
            true, // enabled 
            true, // account not expired
            true, // credentials not expired 
            true, // account not locked
            authorities);
    }
...
}

根据AlreadyBuiltException documentation :

Thrown when AbstractSecurityBuilder.build() is two or more times.

但我不明白为什么 spring 会这样做。

任何思考者都将不胜感激。

谢谢大家。

这里我多放了一些CallStack

Caused by: org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'usuarioServiceImpl' defined in file [C:\Users\ely\Documents\Desarrollo\Spring\workspace-sts-3.5.1.RELEASE\ws-timbrado-backend\target\classes\mx\i4b\timbrado\service\entidades\UsuarioServiceImpl.class]: Initialization of bean failed; nested exception is 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]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:547) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:195) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.findAutowireCandidates(DefaultListableBeanFactory.java:1017) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:960) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:858) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:480) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    ... 73 common frames omitted
Caused by: 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]: Instantiation of bean failed; nested exception is org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:597) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.instantiateUsingFactoryMethod(AbstractAutowireCapableBeanFactory.java:1094) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBeanInstance(AbstractAutowireCapableBeanFactory.java:989) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:504) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:475) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:304) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:300) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.security.access.intercept.aopalliance.MethodSecurityMetadataSourceAdvisor.getAdvice(MethodSecurityMetadataSourceAdvisor.java:96) ~[spring-security-core-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.aop.aspectj.AspectJProxyUtils.isAspectJAdvice(AspectJProxyUtils.java:67) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.aop.aspectj.AspectJProxyUtils.makeAdvisorChainAspectJCapableIfNecessary(AspectJProxyUtils.java:49) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.aop.aspectj.autoproxy.AspectJAwareAdvisorAutoProxyCreator.extendAdvisors(AspectJAwareAdvisorAutoProxyCreator.java:97) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.findEligibleAdvisors(AbstractAdvisorAutoProxyCreator.java:89) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAdvisorAutoProxyCreator.getAdvicesAndAdvisorsForBean(AbstractAdvisorAutoProxyCreator.java:69) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.wrapIfNecessary(AbstractAutoProxyCreator.java:376) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.aop.framework.autoproxy.AbstractAutoProxyCreator.postProcessAfterInitialization(AbstractAutoProxyCreator.java:339) ~[spring-aop-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.applyBeanPostProcessorsAfterInitialization(AbstractAutowireCapableBeanFactory.java:421) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1558) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:539) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    ... 82 common frames omitted
Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:188) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.beans.factory.support.ConstructorResolver.instantiateUsingFactoryMethod(ConstructorResolver.java:586) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    ... 101 common frames omitted
Caused by: org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built
    at org.springframework.security.config.annotation.AbstractSecurityBuilder.build(AbstractSecurityBuilder.java:42) ~[spring-security-config-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.security.config.annotation.authentication.configuration.AuthenticationConfiguration.getAuthenticationManager(AuthenticationConfiguration.java:78) ~[spring-security-config-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.authenticationManager(GlobalMethodSecurityConfiguration.java:248) ~[spring-security-config-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor(GlobalMethodSecurityConfiguration.java:119) ~[spring-security-config-3.2.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerBySpringCGLIB$$d8bcec4.CGLIB$methodSecurityInterceptor$8(<generated>) ~[spring-core-4.0.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerBySpringCGLIB$$d8bcec4$$FastClassBySpringCGLIB$$42ba89ef.invoke(<generated>) ~[spring-core-4.0.3.RELEASE.jar:3.2.3.RELEASE]
    at org.springframework.cglib.proxy.MethodProxy.invokeSuper(MethodProxy.java:228) ~[spring-core-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.context.annotation.ConfigurationClassEnhancer$BeanMethodInterceptor.intercept(ConfigurationClassEnhancer.java:312) ~[spring-context-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    at org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration$$EnhancerBySpringCGLIB$$d8bcec4.methodSecurityInterceptor(<generated>) ~[spring-core-4.0.3.RELEASE.jar:3.2.3.RELEASE]
    at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) ~[na:1.7.0_25]
    at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:57) ~[na:1.7.0_25]
    at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) ~[na:1.7.0_25]
    at java.lang.reflect.Method.invoke(Method.java:606) ~[na:1.7.0_25]
    at org.springframework.beans.factory.support.SimpleInstantiationStrategy.instantiate(SimpleInstantiationStrategy.java:166) ~[spring-beans-4.0.3.RELEASE.jar:4.0.3.RELEASE]
    ... 102 common frames omitted  


<小时/>


//////更新 1//////

基于@M.Dainum,我删除了我的authenticationManager

尝试以三种方式定义我的databaseAuthenticationProvider(包含在本文中),但在身份验证时都导致相同的 NullPointerException。

java.lang.NullPointerException: null
    at org.springframework.security.authentication.ProviderManager.authenticate(ProviderManager.java:147) ~[spring-security-core-3.2.3.RELEASE.jar:3.2.3.RELEASE]

ProviderManager.java:147:

        if (!provider.supports(toTest)) {
<删除> - 我不认为“provider”为空,因为我确定我的 Autowiring 的“databaseAuthenticationProvider”不是空的。
- `toTest` 来自 `authentication.getClass()`。它不应该为空。正确的? (不确定我是否远程理解了这个问题)


getProviders() 继续:

[null, org.springframework.security.authentication.AnonymousAuthenticationProvider@490adcdf]

之前犯了一个错误:提供者为空。所以“ Autowiring ”没有发生。

我认为这是因为为了使用类似的东西:auth.authenticationProvider(databaseAuthenticationProvider);databaseAuthenticationProvider应该是静态的,这会阻止 Autowiring 。对吗?

如果我使用“new”创建它,那么之后 messageDigestPasswordEncoder 为 null,依此类推。

那么...我应该如何解决这个问题?

操作1:

    @Configuration
    @Order(1)                                                        
    public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(databaseAuthenticationProvider);
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {

操作2:

    @Configuration
    @Order(1)                                                        
    public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(HttpSecurity http) throws Exception {

            http.authenticationProvider(databaseAuthenticationProvider);

Op3:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig {

    @Autowired
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(databaseAuthenticationProvider);
    }


<小时/>


//////更新 2//////

为了“强制”“ Autowiring ”,尝试从属性中删除 @Autowire 并将其添加到 setter 方法中,如下所示:

public class WebSecurityConfig {
    private static DatabaseAuthenticationProvider databaseAuthenticationProvider;

    @Autowired
    public void setDatabaseAuthenticationProvider(DatabaseAuthenticationProvider databaseAuthenticationProvider) {
        WebSecurityConfig.databaseAuthenticationProvider = databaseAuthenticationProvider;
    }

    @Configuration
    @Order(1)                                                        
    public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            if (databaseAuthenticationProvider == null) {
                System.out.println("************************************************* databaseAuthenticationProvider es null");
            } else {
                System.out.println("************************************************* databaseAuthenticationProvider NO ES NULL");
            }
            auth.authenticationProvider(databaseAuthenticationProvider);
        }

现在:回到第一方:

Caused by: org.springframework.beans.factory.BeanDefinitionStoreException: Factory method [public org.aopalliance.intercept.MethodInterceptor org.springframework.security.config.annotation.method.configuration.GlobalMethodSecurityConfiguration.methodSecurityInterceptor() throws java.lang.Exception] threw exception; nested exception is org.springframework.security.config.annotation.AlreadyBuiltException: This object has already been built

我想问题不在于我有自己的AuthenticationManager 其他地方正在 build 两次。

如何找到它?

顺便说一句......它仍然有空值:

************************************************* databaseAuthenticationProvider es null

最佳答案

我要感谢 M.Deinum。我终于让它工作了。

就这么简单:

@Configuration
@EnableGlobalMethodSecurity(securedEnabled = true)
public class WebSecurityConfig {

    @Configuration
    @Order(1)                                                        
    public static class RestWebSecurityConfigurationAdapter extends WebSecurityConfigurerAdapter {

        @Autowired
        private  DatabaseAuthenticationProvider databaseAuthenticationProvider;

        @Override
        protected void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(databaseAuthenticationProvider);
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http
                .authorizeRequests()
                    .antMatchers(HttpMethod.GET, "/usuario/*/rfc/*").authenticated()
...

现在我的服务方法只能由指定的角色访问,如下所示:

@Secured({Sec.R_ADMIN})
Usuario getUsuarioByEmisorAndIdUsuario(Emisor emisor, String idUsuario, boolean consultarRoles) throws AuthorizationException;

存在:

public class Sec {
    public static final String R_ADMIN = "ROLE_ADMIN";

关于spring - 再次... Spring Boot/security 的方法安全性 : Error creating bean with name 'methodSecurityInterceptor' "This object has already been built",我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/24945534/

相关文章:

java - 在 Web 应用程序中记录用户 Activity

java - Spring Security 4.指定访问决策管理器时出现异常

java - 服务器重启后 HttpSession 仍然存在

java - 在运行时创建的对象中使用 Autowiring 的 bean

java - 使用 ZK 配置 AOP 以拦截方法

java - Thymeleaf SpringEL 表达式

java - 如何在具有 Spring Boot 后端的 Vue.js 应用程序中包含 CSRF token ?

spring - 当我已经有集成测试时,我应该为 CRUD 操作编写单元测试吗?

java - 第二个自动连接的 REST 存储库不工作

java - 如何将内部类添加到 Spring 应用程序上下文以进行单元测试?