没有找到类型为[PATHTOCLASS]的限定bean用于依赖:预期至少有1个bean有资格作为此依赖项的autowire候选者

时间:2016-11-18 10:28:16

标签: java spring spring-mvc spring-security autowired

我已经尝试了至少2天的时间来运行我的应用程序,但没有任何成功 我不知道为什么例如类JwtAuthenticationProvider不被识别为Bean,因此在类MasterprojectSecurityConfiguration中成功自动装配。

我正在使用Spring 4.3.0和Java 1.8的基于Java的配置。 问题是,当Tomcat部署war-file时,每次尝试在MasterprojectSecurityConfiguration中自动装配类(@Component)都会导致以下异常:

18-Nov-2016 10:45:16.099 INFO [localhost-startStop-4] org.apache.catalina.core.ApplicationContext.log 2 Spring WebApplicationInitializers detected on classpath
18-Nov-2016 10:45:16.267 INFO [localhost-startStop-4] org.apache.catalina.core.ApplicationContext.log Initializing log4j from [/var/lib/tomcat8-masterproject/webapps/masterproject/WEB-INF/classes/_dev/log4j.xml]
18-Nov-2016 10:45:16.325 INFO [localhost-startStop-4] org.apache.catalina.core.ApplicationContext.log Initializing Spring root WebApplicationContext
18-Nov-2016 10:45:22.559 SEVERE [localhost-startStop-4] org.apache.catalina.core.StandardContext.listenerStart 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 'masterprojectSecurityConfiguration': Unsatisfied dependency expressed through field 'jwtAuthenticationProvider': No qualifying bean of type [at.oase.masterproject.security.jwt.JwtAuthenticationProvider] found for dependency [at.oase.masterproject.security.jwt.JwtAuthenticationProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}; nested exception is org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [at.oase.masterproject.security.jwt.JwtAuthenticationProvider] found for dependency [at.oase.masterproject.security.jwt.JwtAuthenticationProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:573)
        at org.springframework.beans.factory.annotation.InjectionMetadata.inject(InjectionMetadata.java:88)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor.postProcessPropertyValues(AutowiredAnnotationBeanPostProcessor.java:350)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.populateBean(AbstractAutowireCapableBeanFactory.java:1214)
        at org.springframework.beans.factory.support.AbstractAutowireCapableBeanFactory.doCreateBean(AbstractAutowireCapableBeanFactory.java:543)
        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:775)
        at org.springframework.context.support.AbstractApplicationContext.finishBeanFactoryInitialization(AbstractApplicationContext.java:861)
        at org.springframework.context.support.AbstractApplicationContext.refresh(AbstractApplicationContext.java:541)
        at org.springframework.web.context.ContextLoader.configureAndRefreshWebApplicationContext(ContextLoader.java:444)
        at org.springframework.web.context.ContextLoader.initWebApplicationContext(ContextLoader.java:326)
        at org.springframework.web.context.ContextLoaderListener.contextInitialized(ContextLoaderListener.java:107)
        at org.apache.catalina.core.StandardContext.listenerStart(StandardContext.java:4795)
        at org.apache.catalina.core.StandardContext.startInternal(StandardContext.java:5221)
        at org.apache.catalina.util.LifecycleBase.start(LifecycleBase.java:150)
        at org.apache.catalina.core.ContainerBase.addChildInternal(ContainerBase.java:724)
        at org.apache.catalina.core.ContainerBase.addChild(ContainerBase.java:700)
        at org.apache.catalina.core.StandardHost.addChild(StandardHost.java:714)
        at org.apache.catalina.startup.HostConfig.deployWAR(HostConfig.java:919)
        at org.apache.catalina.startup.HostConfig$DeployWar.run(HostConfig.java:1703)
        at java.util.concurrent.Executors$RunnableAdapter.call(Executors.java:511)
        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: org.springframework.beans.factory.NoSuchBeanDefinitionException: No qualifying bean of type [at.oase.masterproject.security.jwt.JwtAuthenticationProvider] found for dependency [at.oase.masterproject.security.jwt.JwtAuthenticationProvider]: expected at least 1 bean which qualifies as autowire candidate for this dependency. Dependency annotations: {@org.springframework.beans.factory.annotation.Autowired(required=true)}
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.raiseNoSuchBeanDefinitionException(DefaultListableBeanFactory.java:1398)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.doResolveDependency(DefaultListableBeanFactory.java:1051)
        at org.springframework.beans.factory.support.DefaultListableBeanFactory.resolveDependency(DefaultListableBeanFactory.java:1018)
        at org.springframework.beans.factory.annotation.AutowiredAnnotationBeanPostProcessor$AutowiredFieldElement.inject(AutowiredAnnotationBeanPostProcessor.java:570)
        ... 28 more

在我看来,我还有以下相关文件。

MasterprojectWebAppInitializer.java

package at.oase.masterproject.config;

import javax.servlet.Filter;
import javax.servlet.ServletContext;
import javax.servlet.ServletException;

import org.springframework.web.WebApplicationInitializer;
import org.springframework.web.filter.CharacterEncodingFilter;
import org.springframework.web.servlet.support.AbstractAnnotationConfigDispatcherServletInitializer;
import org.springframework.web.util.Log4jConfigListener;

import at.oase.masterproject.listener.MasterprojectContextLoaderListener;

/**
 * Ersatz für die web.xml
 * @author djanesch
 * @version %I%, %G% 
 * Createdate 17.11.2016 08:42:27
 *
 */
@SuppressWarnings("deprecation")
public class MasterprojectWebAppInitializer extends AbstractAnnotationConfigDispatcherServletInitializer implements WebApplicationInitializer {

  @Override
  public void onStartup(final ServletContext servletContext) throws ServletException {
    final String log4jConfigLocationParam = "log4jConfigLocation";
    servletContext.setInitParameter(log4jConfigLocationParam, "/WEB-INF/classes/${environment}/log4j.xml");
    servletContext.setInitParameter("log4jExposeWebAppRoot", "false");
    servletContext.addListener(Log4jConfigListener.class);
    super.onStartup(servletContext);
  }

  /**
   * Wird typischerweise root oder parent configuration genannt und kann keine Beans von Klassen welche in getServletConfigClasses definiert wurden sehen!
   * HINWEIS: return null, if you don't use both root and servlet context
   * Any configuration within getRootConfigClasses is typically called the root or parent configuration and cannot view beans defined in getServletConfigClasses. 
   * Spring Security protects your application defined in the getRootConfigClasses with a Filter named springSecurityFilterChain that is created by the @EnableWebSecurity annotation. 
   * This means it is generally best to place Spring Security's configuration in the getRootConfigClasses. 
   * There are some exceptions to this, like if you want to do method security on your Spring MVC Controllers.
   */
  @Override
  protected Class<?>[] getRootConfigClasses() {
    return new Class[] { MasterprojectDatabaseConfiguration.class, MasterprojectSecurityConfiguration.class };
  }

  /**
   * Wird typischerweise child configuration genannt und kann Beans von Klassen welche in getRootConfigClasses definiert wurden sehen!
   * HINWEIS: return null, if you don't use both root and servlet context
   * Any configuration within getServletConfigClasses is typically called the child configuration and can view beans defined in the getRootConfigClasses. 
   * The getServletConfigClasses configures the DispatcherServlet and must contain beans for Spring MVC (i.e. Controllers, ViewResovlers, etc). 
   * Any Spring MVC beans defined in getRootConfigClasses are visible but not used.
   */
  @Override
  protected Class<?>[] getServletConfigClasses() {
    return new Class[] { MasterprojectMVCConfiguration.class };
  }

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

  /**
   * returned filters will be register to dispatcherServlet
   */
  @Override
  protected Filter[] getServletFilters() {
    CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter();
    characterEncodingFilter.setEncoding("UTF-8");
    characterEncodingFilter.setForceEncoding(true);
    return new Filter[] { characterEncodingFilter };
  }

  @Override
  protected void registerDispatcherServlet(ServletContext servletContext) {
    super.registerDispatcherServlet(servletContext);
    servletContext.addListener(new MasterprojectContextLoaderListener());
  }
}

MasterprojectSecurityConfiguration.java

package at.oase.masterproject.config;

import javax.sql.DataSource;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Configuration;
import org.springframework.core.annotation.Order;
import org.springframework.security.authentication.dao.DaoAuthenticationProvider;
import org.springframework.security.config.annotation.authentication.builders.AuthenticationManagerBuilder;
import org.springframework.security.config.annotation.web.builders.HttpSecurity;
import org.springframework.security.config.annotation.web.builders.WebSecurity;
import org.springframework.security.config.annotation.web.configuration.EnableWebSecurity;
import org.springframework.security.config.annotation.web.configuration.WebSecurityConfigurerAdapter;
import org.springframework.security.config.http.SessionCreationPolicy;
import org.springframework.security.core.userdetails.jdbc.JdbcDaoImpl;
import org.springframework.security.crypto.bcrypt.BCryptPasswordEncoder;

import at.oase.masterproject.security.jwt.JwtAuthenticationProvider;


@Configuration
@EnableWebSecurity // erzeugt springSecurityFilterChain
public class MasterprojectSecurityConfiguration extends WebSecurityConfigurerAdapter {
  public static final String JWT_TOKEN_HEADER_PARAM = "X-Authorization";
  public static final String FORM_BASED_LOGIN_ENTRY_POINT = "/login";
  public static final String TOKEN_BASED_AUTH_ENTRY_POINT = "/**";
  public static final String TOKEN_REFRESH_ENTRY_POINT = "/token";

  @Autowired private JwtAuthenticationProvider jwtAuthenticationProvider;

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

        @Autowired
        private DataSource dataSource;

        @Autowired
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(getAuthenticationProvider(dataSource));
        }

        @Override
        public void configure(WebSecurity web) throws Exception {
            web.ignoring().antMatchers("/resources/**");
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests()
                    .antMatchers("/login", "/loginfailed", "/logout", "/sessioninvalid",
                            "/sessionexpired")
                    .permitAll().anyRequest().hasAuthority("recht.backend").and().formLogin().loginPage("/login")
                    .usernameParameter("j_username").passwordParameter("j_password").failureUrl("/login?error")
                    .defaultSuccessUrl("/home").and().exceptionHandling().and().csrf().disable();
        }
    }

    @Configuration
    @Order(2)
    public static class FehlerSecurityAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private DataSource dataSource;

        @Autowired
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(getAuthenticationProvider(dataSource));
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().antMatchers("/fehler/**").authenticated().and().httpBasic().and()
                    .sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and().csrf().disable();
        }
    }

    @Configuration
    @Order(3)
    public static class SchnittstelleSecurityAdapter extends WebSecurityConfigurerAdapter {
        @Autowired
        private DataSource dataSource;

        @Autowired
        public void configure(AuthenticationManagerBuilder auth) throws Exception {
            auth.authenticationProvider(getAuthenticationProvider(dataSource));
        }

        @Override
        protected void configure(HttpSecurity http) throws Exception {
            http.authorizeRequests().antMatchers("/schnittstelle/**").hasAuthority("recht.schnittstelle").and()
                    .httpBasic().and().sessionManagement().sessionCreationPolicy(SessionCreationPolicy.STATELESS).and()
                    .csrf().disable();
        }
    }

    public static String getUserQuery() {
        return "SELECT b.login AS \"username\", b.passwort AS \"password\", b.aktiv AS \"enabled\" "
                + "FROM kern_benutzer b " + "WHERE b.login=? " + "AND b.deleteuser IS NULL AND b.deletedate IS NULL";
    }

    public static String getAuthoritiesQuery() {
        return "SELECT g.id AS \"id\", g.sprachschluessel AS \"group_name\", r.sprachschluessel AS \"authority\" "
                + "FROM kern_benutzer b " + "INNER JOIN kern_benutzer_gruppe bg ON (bg.fk_kern_benutzer=b.id) "
                + "INNER JOIN kern_gruppe g ON (bg.fk_kern_gruppe=g.id) "
                + "INNER JOIN kern_recht_gruppe rg ON (rg.fk_kern_gruppe=g.id) "
                + "INNER JOIN kern_recht r ON (rg.fk_kern_recht=r.id) " + "WHERE b.login=? "
                + "AND b.deleteuser IS NULL AND b.deletedate IS NULL "
                + "AND bg.deleteuser IS NULL AND bg.deletedate IS NULL "
                + "AND g.deleteuser IS NULL AND g.deletedate IS NULL "
                + "AND rg.deleteuser IS NULL AND rg.deletedate IS NULL "
                + "AND r.deleteuser IS NULL AND r.deletedate IS NULL";
    }

    public static DaoAuthenticationProvider getAuthenticationProvider(DataSource dataSource){
        JdbcDaoImpl userDetailsService = new JdbcDaoImpl();
        userDetailsService.setDataSource(dataSource);
        userDetailsService.setEnableAuthorities(false);
        userDetailsService.setEnableGroups(true);
        userDetailsService.setUsersByUsernameQuery(getUserQuery());
        userDetailsService.setGroupAuthoritiesByUsernameQuery(getAuthoritiesQuery());

        DaoAuthenticationProvider authenticationProvider = new DaoAuthenticationProvider();
        authenticationProvider.setUserDetailsService(userDetailsService);
        authenticationProvider.setPasswordEncoder(new BCryptPasswordEncoder());
        /**
         * Es wird jetzt der neu PasswordEncoder "BCryptPasswordEncoder" verwendt,
         * welcher  automatisch dem Passwort ein Salt hinzufügt
         * 
        ReflectionSaltSource saltSource = new ReflectionSaltSource();
        saltSource.setUserPropertyToUse("username");
        authenticationProvider.setSaltSource(saltSource);*/
        return authenticationProvider;
    }
}

MasterprojectMVCConfiguration.java

package at.oase.masterproject.config;

import java.util.Locale;

import org.springframework.context.annotation.Bean;
import org.springframework.context.annotation.ComponentScan;
import org.springframework.context.annotation.Configuration;
import org.springframework.context.support.ReloadableResourceBundleMessageSource;
import org.springframework.web.multipart.commons.CommonsMultipartResolver;
import org.springframework.web.servlet.ViewResolver;
import org.springframework.web.servlet.config.annotation.CorsRegistry;
import org.springframework.web.servlet.config.annotation.DefaultServletHandlerConfigurer;
import org.springframework.web.servlet.config.annotation.EnableWebMvc;
import org.springframework.web.servlet.config.annotation.InterceptorRegistry;
import org.springframework.web.servlet.config.annotation.ResourceHandlerRegistry;
import org.springframework.web.servlet.config.annotation.WebMvcConfigurerAdapter;
import org.springframework.web.servlet.i18n.LocaleChangeInterceptor;
import org.springframework.web.servlet.i18n.SessionLocaleResolver;
import org.springframework.web.servlet.view.InternalResourceViewResolver;
import org.springframework.web.servlet.view.JstlView;

import at.oase.masterproject.interceptor.LayoutInterceptor;
import dummiesmind.breadcrumb.springmvc.interceptor.BreadCrumbInterceptor;

@Configuration
@EnableWebMvc
@ComponentScan("at.oase") // Durchsucht at.oase und alles darunter nach @Component (@Component, @Repository, @Service und @Controller) Klassen
public class MasterprojectMVCConfiguration extends WebMvcConfigurerAdapter {

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

  @Bean
  public ViewResolver viewResolver() {
    InternalResourceViewResolver viewResolver = new InternalResourceViewResolver();
    viewResolver.setViewClass(JstlView.class);
    viewResolver.setPrefix("/WEB-INF/views/");
    viewResolver.setSuffix(".jsp");
    return viewResolver;
  }

  @Bean
  public ReloadableResourceBundleMessageSource messageSource() {
    ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource();
    messageSource.setDefaultEncoding("UTF-8");
    messageSource.setFallbackToSystemLocale(false);
    messageSource.setUseCodeAsDefaultMessage(true);
    messageSource.setBasename("classpath:i18n/nachrichten");
    return messageSource;
  }

  @Bean(name="localeResolver")
  public SessionLocaleResolver sessionLocaleResolver() {
    SessionLocaleResolver sessionLocaleResolver = new SessionLocaleResolver();
    sessionLocaleResolver.setDefaultLocale(new Locale("de","DE"));
    return sessionLocaleResolver;
  }

  @Bean
  public CommonsMultipartResolver commonsMultipartResolver() {
    CommonsMultipartResolver commonsMultipartResolver = new CommonsMultipartResolver();
    commonsMultipartResolver.setDefaultEncoding("UTF-8");
    return commonsMultipartResolver;
  } 

  @Override
  public void addInterceptors(InterceptorRegistry registry) {
    LayoutInterceptor lic = new LayoutInterceptor();
    lic.setLayoutLogin("layoutLogin");
    lic.setLayoutView("layout");
    registry.addInterceptor(lic);
    LocaleChangeInterceptor interceptor = new LocaleChangeInterceptor();
    interceptor.setParamName("sprache");
    registry.addInterceptor(interceptor);
    BreadCrumbInterceptor bic = new BreadCrumbInterceptor();
    registry.addInterceptor(bic);
  }

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

  @Override
  public void addCorsMappings(CorsRegistry registry) {
    registry.addMapping("/**")
      .allowedOrigins("http://localhost:4200")
//      .allowedMethods("PUT", "DELETE")
//      .allowedHeaders("header1", "header2", "header3")
//      .exposedHeaders("header1", "header2")
//      .allowCredentials(false).maxAge(3600)
      ;
  }
}

JwtAuthenticationProvider.java

package at.oase.masterproject.security.jwt;

import java.util.List;
import java.util.stream.Collectors;

import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.security.authentication.AuthenticationProvider;
import org.springframework.security.core.Authentication;
import org.springframework.security.core.AuthenticationException;
import org.springframework.security.core.GrantedAuthority;
import org.springframework.security.core.authority.SimpleGrantedAuthority;
import org.springframework.stereotype.Component;

import at.oase.masterproject.config.MasterprojectConfig;
import at.oase.masterproject.security.JwtAuthenticationToken;
import at.oase.masterproject.security.UserContext;
import at.oase.masterproject.security.token.JwtToken;
import at.oase.masterproject.security.token.RawAccessJwtToken;
import io.jsonwebtoken.Claims;
import io.jsonwebtoken.Jws;

/**
 * An {@link AuthenticationProvider} implementation that will use provided
 * instance of {@link JwtToken} to perform authentication.
 * 
 * @author vladimir.stankovic
 *
 * Aug 5, 2016
 */
@Component
@SuppressWarnings("unchecked")
public class JwtAuthenticationProvider implements AuthenticationProvider {
  private final MasterprojectConfig config;

  @Autowired
  public JwtAuthenticationProvider(MasterprojectConfig config) {
      this.config = config;
  }

  @Override
  public Authentication authenticate(Authentication authentication) throws AuthenticationException {
    RawAccessJwtToken rawAccessToken = (RawAccessJwtToken) authentication.getCredentials();

    Jws<Claims> jwsClaims = rawAccessToken.parseClaims(config.getTokenSigningKey());
    String subject = jwsClaims.getBody().getSubject();
    List<String> scopes = jwsClaims.getBody().get("scopes", List.class);
    List<GrantedAuthority> authorities = scopes.stream()
      .map(authority -> new SimpleGrantedAuthority(authority))
      .collect(Collectors.toList());
    UserContext context = UserContext.create(subject, authorities);

    return new JwtAuthenticationToken(context);
  }

  @Override
  public boolean supports(Class<?> authentication) {
    return (JwtAuthenticationToken.class.isAssignableFrom(authentication));
  }
}

1 个答案:

答案 0 :(得分:-1)

您正在自动连接类(JwtAuthenticationProvider),但它需要是一个接口,因为Spring根据接口创建并使用代理对象。创建这样的东西:

@Component
public interface JwtAuthenticationProviderService implements AuthenticationProvider {

public Authentication authenticate(Authentication authentication)

public boolean supports(Class<?> authentication)
}

然后让你的JwtAuthenticationProvider类实现这个新接口,然后@Autowire这个服务接口。某处可能存在一些更深层次的问题,但我的猜测是应该解决这个问题。