Как загрузить пользовательский DaoAuthenticationProvider в контекст Spring?

У меня есть эта проблема с Spring Security.

У меня есть реализация java-config с классом SecurityConfig, который расширяет WebSecurityConfigurerAdapter.

В этом классе я хочу переопределить метод "configure()"

@Configuration
@EnableWebSecurity
@EnableGlobalMethodSecurity(prePostEnabled = true, securedEnabled = true, proxyTargetClass = true)
public class SecurityConfig extends WebSecurityConfigurerAdapter{

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        MyDaoAuthenticationProvider provider = new MyDaoAuthenticationProvider();
        provider.setPasswordEncoder(passwordEncoder());
        provider.setUserDetailsService(securityService);
        auth.authenticationProvider(provider);
    }

    //...

}   

Все в порядке, и это работает.

Проблема в том, что компонент "MyDaoAuthenticationProvider" не загружен в контексте Spring. Поэтому я не могу внедрить или автоматически подключить какие-либо компоненты в этом классе:

public class MyDaoAuthenticationProvider extends DaoAuthenticationProvider {

    @Autowired
    AuthenticationHandler authenticationHandler;    // <- authenticationHandler is null, is not resolved

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        authenticationHandler.authenticate(authentication);    // <- NullPointerException in this point
    }

}

Это класс AuthenticationHandler:

@Component
public class AuthenticationHandler {

    public void authenticate (Authentication authentication) {
        // do stuff
    }

}

Если я добавлю @Component в класс MyDaoAuthenticationProvider и добавлю аннотацию @Autowired в класс SecurityConfig:

@Autowired
MyDaoAuthenticationProvider provider;

сбой приложения при запуске с этой ошибкой:

org.springframework.beans.factory.BeanCreationException: Error creating bean with name 'myDaoAuthenticationProvider' defined in file [...\MyDaoAuthenticationProvider.class]: Invocation of init method failed; nested exception is java.lang.IllegalArgumentException: A UserDetailsService must be set
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1578)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:545)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:482)
    at org.springframework.beans.factory.support.AbstractBeanFactory$1.getObject(AbstractBeanFactory.java:306)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:230)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:302)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:197)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:772)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:839)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:538)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:446)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:328)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4812)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5255)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1408)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1398)
    at java.util.concurrent.FutureTask.run(FutureTask.java:266)
    at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142)
    at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617)
    at java.lang.Thread.run(Thread.java:745)
Caused by: java.lang.IllegalArgumentException: A UserDetailsService must be set
    at org.springframework.util.Assert.notNull(Assert.java:115)
    at org.springframework.security.authentication.dao.DaoAuthenticationProvider.doAfterPropertiesSet(DaoAuthenticationProvider.java:105)
    at org.springframework.security.authentication.dao.AbstractUserDetailsAuthenticationProvider.afterPropertiesSet(AbstractUserDetailsAuthenticationProvider.java:122)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.invokeInitMethods(AbstractAutowireCapableBeanFactory.java:1637)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.initializeBean(AbstractAutowireCapableBeanFactory.java:1574)
    ... 21 more

Что я должен сделать, чтобы решить эту проблему? Благодарю.

РЕДАКТИРОВАТЬ

РЕШЕНИЕ

Благодаря OrangeDog я исправил проблему с этой реализацией:

@Bean
public MyDaoAuthenticationProvider myAuthProvider() throws Exception {
    MyDaoAuthenticationProvider provider = new MyDaoAuthenticationProvider();
    provider.setPasswordEncoder(passwordEncoder());
    provider.setUserDetailsService(securityService);
    return provider;
}

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

В этой конфигурации бин правильно инициализирован, и больше нет ошибки "java.lang.IllegalArgumentException: должен быть установлен UserDetailsService".

Кроме того, компонент загружается в контекст Spring, поэтому все внедренные компоненты в DaoAuthenticationProvider правильно разрешены.

1 ответ

Решение

Ошибка создания бина с именем 'myDaoAuthenticationProvider' [...] Должна быть установлена ​​служба UserDetailsService

Ваш MyDaoAuthenticationProvider не имеет UserDetailsService, Вы должны внедрить, внедрить и / или установить один. Например, без использования @Component:

@Bean
public MyDaoAuthenticationProvider myAuthProvider() {
    MyDaoAuthenticationProvider provider = new MyDaoAuthenticationProvider();
    provider.setPasswordEncoder(passwordEncoder());
    provider.setUserDetailsService(securityService);
    return provider;
}

Затем вам нужно прекратить создавать еще один в вашем configure метод.


Если вы не думаете, что вам это нужно, то вам, вероятно, не следует реализовывать DaoAuthenticationProvider, Возможно, вы действительно хотите реализовать общий AuthenticationProviderили использование его других реализующих классов.

Другие вопросы по тегам