0

I keep getting the above error when trying to implement spring-security. Please kindly help out as i'm fairly new to spring mvc

I have tried using solutions provided on

No qualifying bean of type available in SpringBoot Application

No qualifying bean of type 'concert.PerformanceImp' available

and some others but i couldn't figure out why the issue still persist

My Codes


/** spring security configurer **/

@Configuration
@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    MyUserDetailsService userDetailsService;    


    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }


    @Override
    protected void configure (HttpSecurity http) throws Exception {
        http
            .authorizeRequests()
                /**
                 * None of these urls requires authentication and any other urls
                 * not specified here, will require authentication
                 */
                .antMatchers(
                        "/", 
                        "/about", 
                        "/account/create"
                ).permitAll();

        http
            .formLogin()
                .loginPage("/account/login")
                .usernameParameter("email")
                .permitAll()
                .and()
                    .logout()
                    .permitAll();
    }
}



/** Custom UserDetailsService **/
@Service
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private AccountDao accountDao;

    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        Account account = accountDao.findAccountByEmail(email);
        System.out.println("User " + account );

        if(account == null ) {
            throw new UsernameNotFoundException(
                    "User " + email + " was not found in database");
        }

        return (UserDetails) account;
    }
}




/** Front Controller **/

@Configuration
@EnableWebMvc

// the package set on component scan is the parent package, and every other packages are within it
// as some suggestions from slackoverflow pointed that it could be that the package of 
// MyUserDetailsService is not seen by the component scan 

@ComponentScan(basePackages= {"com.springmvcproject.concertio"})
public class FrontController implements WebMvcConfigurer {

    @Bean(name="messageSource")
    public MessageSource getMessageSource() {
        ResourceBundleMessageSource messageSource = new ResourceBundleMessageSource();
        messageSource.setBasename("messages");
        return messageSource;
    }


    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {
        registry.addResourceHandler("/concertio/resources/**").addResourceLocations("/")
        .setCachePeriod(31556926);
    }


    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) {
        configurer.enable();
    }



    @Bean
    InternalResourceViewResolver viewResolver(){
        InternalResourceViewResolver resolver = new InternalResourceViewResolver();
        resolver.setPrefix("/WEB-INF/views/");
        resolver.setSuffix(".jsp");
        resolver.setRequestContextAttribute("requestContext");

        return resolver;
    }

}

Server Error Log

Nov 06, 2019 6:01:37 PM org.apache.catalina.core.StandardContext listenerStart
SEVERE: Exception sending context initialized event to listener instance of class [org.springframework.web.context.ContextLoaderListener]
org.springframework.beans.factory.UnsatisfiedDependencyException: Error creating bean with name 'securityConfig': Unsatisfied dependency expressed through field 'userDetailsService'; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.springmvcproject.concertio.service.MyUserDetailsService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:581)
    at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:91)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:367)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1340)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:582)
    at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.createBean(AbstractAutowireCapableBeanFactory.java:502)
    at org.springframework.beans.factory.support.AbstractBeanFactory.lambda$doGetBean$0(AbstractBeanFactory.java:312)
    at org.springframework.beans.factory.support.DefaultSingletonBeanRegistry.getSingleton(DefaultSingletonBeanRegistry.java:228)
    at org.springframework.beans.factory.support.AbstractBeanFactory.doGetBean(AbstractBeanFactory.java:310)
    at org.springframework.beans.factory.support.AbstractBeanFactory.getBean(AbstractBeanFactory.java:200)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.preInstantiateSingletons(DefaultListableBeanFactory.java:756)
    at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:868)
    at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:549)
    at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:409)
    at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:291)
    at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:103)
    at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4666)
    at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5136)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1377)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1367)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:902)
    at org.apache.catalina.core.StandardHost.startInternal(StandardHost.java:831)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1377)
    at org.apache.catalina.core.ContainerBase$StartChild.call(ContainerBase.java:1367)
    at java.base/java.util.concurrent.FutureTask.run(FutureTask.java:264)
    at org.apache.tomcat.util.threads.InlineExecutorService.execute(InlineExecutorService.java:75)
    at java.base/java.util.concurrent.AbstractExecutorService.submit(AbstractExecutorService.java:140)
    at org.apache.catalina.core.ContainerBase.startInternal(ContainerBase.java:902)
    at org.apache.catalina.core.StandardEngine.startInternal(StandardEngine.java:262)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardService.startInternal(StandardService.java:423)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.core.StandardServer.startInternal(StandardServer.java:928)
    at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:183)
    at org.apache.catalina.startup.Catalina.start(Catalina.java:638)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke0(Native Method)
    at java.base/jdk.internal.reflect.NativeMethodAccessorImpl.invoke(NativeMethodAccessorImpl.java:62)
    at java.base/jdk.internal.reflect.DelegatingMethodAccessorImpl.invoke(DelegatingMethodAccessorImpl.java:43)
    at java.base/java.lang.reflect.Method.invoke(Method.java:567)
    at org.apache.catalina.startup.Bootstrap.start(Bootstrap.java:350)
    at org.apache.catalina.startup.Bootstrap.main(Bootstrap.java:492)
Caused by: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type 'com.springmvcproject.concertio.service.MyUserDetailsService' available: expected at least 1 bean which qualifies as autowire candidate. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoMatchingBeanFound(DefaultListableBeanFactory.java:1501)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1099)
    at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1060)
    at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:578)
    ... 45 more

Nov 06, 2019 6:01:37 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: One or more listeners failed to start. Full details will be found in the appropriate container log file
Nov 06, 2019 6:01:37 PM org.apache.catalina.core.StandardContext startInternal
SEVERE: Context [/concertio] startup failed due to previous errors
Nov 06, 2019 6:01:37 PM org.apache.catalina.core.ApplicationContext log
INFO: Closing Spring root WebApplicationContext
Nov 06, 2019 6:01:37 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["http-nio-8080"]
Nov 06, 2019 6:01:37 PM org.apache.coyote.AbstractProtocol start
INFO: Starting ProtocolHandler ["ajp-nio-8009"]
Nov 06, 2019 6:01:37 PM org.apache.catalina.startup.Catalina start
INFO: Server startup in [7,536] milliseconds

I have also used the same step followed by the OP here

Spring security Cant autowire UserDetailsService

but the error still persist... Any help will be highly appreciated

spaceofmiah
  • 238
  • 2
  • 17
  • Many times, it's only the anotation `@Service` or `@Component` that has been forgotten above the `MyUserDetailsService` class in it's implementation ! – Marc Le Bihan Nov 06 '19 at 17:24
  • I think i have `@Service` annotation available in the implementation of `MyUserDetailsService` class – spaceofmiah Nov 06 '19 at 17:35
  • @Jeremy Use @ComponentScan for SecurityConfig where it should scan for available components in its base package. As the order will be rootContext first and servletContext next. your rootContext (`SecurityConfig`) doesn't know the components declared. But your servletContext(`FrontController`) loads after the rootContext has been loaded, at the time of rootContext load it can't find component/bean with your `myUserDetailsService`. Make sure you add ComponentScan for your security configuration. – PraveenKumar Lalasangi Nov 06 '19 at 19:08
  • try to use `UserDetailsService` interface as `@Autowired` – Jonathan JOhx Nov 06 '19 at 19:36
  • @PraveenKumarLalasangi and to all that contributed, thanks a lot. Just as PraveenKumar has explained, that is the exact reason for the error. and with his suggestion and that of Jonathan Johx, i was able to fix the above error... – spaceofmiah Nov 06 '19 at 22:35

2 Answers2

1

Through the help of @PraveenKumarLalasangi, i was able to fix the above error...

This is the current working code base

SecurityConfig


@EnableWebSecurity
public class SecurityConfig extends WebSecurityConfigurerAdapter {

    @Autowired
    private UserDetailsService userDetailsService;


    @Autowired
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.userDetailsService(userDetailsService);
    }

    .....
    .....
    .....

}

MyUserDetailsService

@Component
public class MyUserDetailsService implements UserDetailsService {

    @Autowired
    private AccountDao accountDao;

    @Transactional(readOnly=true)
    @Override
    public UserDetails loadUserByUsername(String email) throws UsernameNotFoundException {
        Account account = accountDao.findAccountByEmail(email);
        System.out.println("User " + account );

        if(account == null ) {
            throw new UsernameNotFoundException(
                    "User " + email + " was not found in database");
        }

        return (UserDetails) account;
    }
}

FrontController


@Configuration
@EnableWebMvc
@ComponentScan(basePackages= {"com.springmvcproject.concertio"})
public class FrontController implements WebMvcConfigurer {
     @Bean(name="messageSource")
    public MessageSource getMessageSource() { .....  }

    @Override
    public void addResourceHandlers(ResourceHandlerRegistry registry) {....}

    @Override
    public void configureDefaultServletHandling(DefaultServletHandlerConfigurer configurer) { .... }

   @Bean
    InternalResourceViewResolver viewResolver(){ .... }
}

WebConfig

public class WebConfig extends AbstractAnnotationConfigDispatcherServletInitializer{

    @Override
    protected Class<?>[] getRootConfigClasses() {
        // TODO Auto-generated method stub
        return null;
    }

    @Override
    protected Class<?>[] getServletConfigClasses() {
        return new Class<?>[] {
            FrontController.class
        };
    }

    @Override
    protected String[] getServletMappings() {
        return new String[] {
            "/" 
        };
    }

}

I hope someone finds this helpful

spaceofmiah
  • 238
  • 2
  • 17
-1

Spring uses its configuration to find and construct its context. And as a part of its configuration you specify where (in which package(s)) the bean classes are located. @ComponentScan(basePackages= {"com.springmvcproject.concertio"}) tells Spring are beans are associated with the com.springmvcproject.concertio package or its sub packages. Is the MyUserDetailsService class placed in this package or sub packages?