Just i dont understand, why customUserDetailsService doesn’t autowire There are 2 classes i use
@Service("customUserDetailsService") public class CustomUserDetailsService implements UserDetailsService { private static final Logger log = LoggerFactory.getLogger(CustomUserDetailsService.class); private UserService userService; @Override @Transactional(readOnly = true) public UserDetails loadUserByUsername(String ssoId) throws UsernameNotFoundException { User user = userService.getUserBySSO(ssoId); log.info("User : {}", user); if (user == null) { log.info("User not found"); throw new UsernameNotFoundException("User not found"); } return new org.springframework.security.core.userdetails.User(user.getSsoId(), user.getPassword(), true, true, true, true, getGrantedAuthorities(user)); } private List<GrantedAuthority> getGrantedAuthorities(User user) { List<GrantedAuthority> grantedAuthorities = new ArrayList<>(); for (Role role : user.getRoles()) { log.info("UserProfile : {}", role); grantedAuthorities.add(new SimpleGrantedAuthority("ROLE_"+role.getRoleName())); } log.info("authorities : {}", grantedAuthorities); return grantedAuthorities; } @Autowired public void setUserService(UserService userService) { this.userService = userService; }
=================
@Configuration @EnableWebSecurity @ComponentScan(basePackages = "ru.mightynoobs.springhibernate.security") public class SpringSecurityConfig extends WebSecurityConfigurerAdapter { private UserDetailsService userDetailsService; private PersistentTokenRepository tokenRepository; @Autowired @Qualifier("customUserDetailsService") public void setUserDetailsService(UserDetailsService userDetailsService) { this.userDetailsService = userDetailsService; } @Autowired @Qualifier("tokenRepositoryDao") public void setTokenRepository(PersistentTokenRepository tokenRepository) { this.tokenRepository = tokenRepository; } @Autowired public void configureGlobalSecurity(AuthenticationManagerBuilder authentication) throws Exception { authentication.userDetailsService(userDetailsService); authentication.authenticationProvider(authenticationProvider()); } @Override protected void configure(HttpSecurity httpSecurity) throws Exception { httpSecurity.authorizeRequests() .antMatchers("/", "/list") .access("hasRole('USER') or hasRole('ADMIN') or hasRole('DBA')") .and() .formLogin().loginPage("/login") .loginProcessingUrl("/login").usernameParameter("ssoId").passwordParameter("pass word") .and() .rememberMe().rememberMeParameter("remember- me").tokenRepository(tokenRepository) .tokenValiditySeconds(86400) .and() .csrf() .and() .exceptionHandling().accessDeniedPage("/access_denied"); } @Bean public PasswordEncoder passwordEncoder() { return new BCryptPasswordEncoder(); } @Bean public PersistentTokenBasedRememberMeServices persistentTokenBasedRememberMeServices() { return new PersistentTokenBasedRememberMeServices("remember-me", userDetailsService, tokenRepository); } @Bean public AuthenticationTrustResolver getAuthenticationTrustResolver() { return new AuthenticationTrustResolverImpl(); } @Bean public DaoAuthenticationProvider authenticationProvider() { DaoAuthenticationProvider daoAuthenticationProvider = new DaoAuthenticationProvider(); daoAuthenticationProvider.setPasswordEncoder(passwordEncoder()); daoAuthenticationProvider.setUserDetailsService(userDetailsService); return daoAuthenticationProvider; } }
And there is stackTrace
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'springSecurityConfig': Unsatisfied dependency expressed through method 'setUserDetailsService' parameter 0; nested exception is org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through method 'setUserService' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'ru.mightynoobs.springhibernate.service.user.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {} at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredMethodElement.inject(AutowiredAnnotationBeanPostProcessor.java:667) at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88) at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:366) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1264) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:553) at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:483) 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:761) at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:867) at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:543) at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:443) at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:325) at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107) at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4743) at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5207) at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150) at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:752) at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:728) at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:734) at org.apache.catalina.startup.HostConfig.manageApp(HostConfig.java:1702) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:482) at org.apache.catalina.mbeans.MBeanFactory.createStandardContext(MBeanFactory.java:431) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at org.apache.tomcat.util.modeler.BaseModelMBean.invoke(BaseModelMBean.java:300) at com.sun.jmx.interceptor.DefaultMBeanServerInterceptor.invoke(DefaultMBeanServerInterceptor.java:819) at com.sun.jmx.mbeanserver.JmxMBeanServer.invoke(JmxMBeanServer.java:801) at javax.management.remote.rmi.RMIConnectionImpl.doOperation(RMIConnectionImpl.java:1468) at javax.management.remote.rmi.RMIConnectionImpl.access$300(RMIConnectionImpl.java:76) at javax.management.remote.rmi.RMIConnectionImpl$PrivilegedOperation.run(RMIConnectionImpl.java:1309) at javax.management.remote.rmi.RMIConnectionImpl.doPrivilegedOperation(RMIConnectionImpl.java:1401) at javax.management.remote.rmi.RMIConnectionImpl.invoke(RMIConnectionImpl.java:829) at sun.reflect.NativeMethodAccessorImpl.invoke0(Native Method) at sun.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62) at sun.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43) at java.lang.reflect.Method.invoke(Method.java:498) at sun.rmi.server.UnicastServerRef.dispatch(UnicastServerRef.java:346) at sun.rmi.transport.Transport$1.run(Transport.java:200) at sun.rmi.transport.Transport$1.run(Transport.java:197) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.Transport.serviceCall(Transport.java:196) at sun.rmi.transport.tcp.TCPTransport.handleMessages(TCPTransport.java:568) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run0(TCPTransport.java:826) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.lambda$run$0(TCPTransport.java:683) at java.security.AccessController.doPrivileged(Native Method) at sun.rmi.transport.tcp.TCPTransport$ConnectionHandler.run(TCPTransport.java:682) 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:748) Caused by: org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'customUserDetailsService': Unsatisfied dependency expressed through method 'setUserService' parameter 0; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'ru.mightynoobs.springhibernate.service.user.UserService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {}
Please explain me, how it’s possible. These classes have the same package, i included this package @ComponentScan annotation. And spring still complains that he cant find @Service Component. There is something easy, but i cant get it. Please help.
Advertisement
Answer
I think you don’t have to mark customUserDetailService
with @Service
annotation. Besides, the db operation and transaction shoule be done in userService to distinguish the duty of each layer. Refactor CustomUserDetailsService
like this:
public class CustomUserDetailsService implements UserDetailsService { // ... @Override public UserDetails loadUserByUsername(String ssoId) throws UsernameNotFoundException { // the implementation } }
And according to Spring Security refence:
5.6.5 UserDetailsService
You can define custom authentication by exposing a custom UserDetailsService as a bean. For example, the following will customize authentication assuming that SpringDataUserDetailsService implements UserDetailsService:
[Note] This is only used if the AuthenticationManagerBuilder has not been populated and no AuthenticationProviderBean is defined.
So remove the bean DaoAuthenticationProvider
in SpringSecurityConfig
and:
@Autowired public void configureGlobalSecurity(AuthenticationManagerBuilder authentication) throws Exception { authentication.userDetailsService(userDetailsServiceBean()); //authentication.authenticationProvider(authenticationProvider()); } @Override @Bean public UserDetailsService userDetailsServiceBean() throws Exception { return new CustomUserDetailsService(); }