Как загрузить пользовательский 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
или использование его других реализующих классов.