我已经尝试了至少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));
}
}
答案 0 :(得分:-1)
您正在自动连接类(JwtAuthenticationProvider
),但它需要是一个接口,因为Spring根据接口创建并使用代理对象。创建这样的东西:
@Component
public interface JwtAuthenticationProviderService implements AuthenticationProvider {
public Authentication authenticate(Authentication authentication)
public boolean supports(Class<?> authentication)
}
然后让你的JwtAuthenticationProvider
类实现这个新接口,然后@Autowire
这个服务接口。某处可能存在一些更深层次的问题,但我的猜测是应该解决这个问题。