6

Dieses Problem wird relativ gut in mehreren Blogposts und SO-Fragen diskutiert. Nichtsdestotrotz konnte ich kein spezielles Problem mit der Java-Konfiguration finden. Ich vermute, dass ich in meinen Java-Konfigurationsdateien etwas falsch mache, da ich einige Posts gefunden habe, die anzeigen, dass das Problem gelöst werden kann, indem das Debug-XML-Tag (https://jira.springsource.org/browse/SEC-1885) entfernt wird.Spring Security 3.2: @Autowire funktioniert nicht mit Java-Konfiguration und benutzerdefinierten AuthenticationProvider in Spring MVC-Anwendung?

Ich benutze 3.2.0.RELEASE der Feder Sicherheit und 3.2.6.RELEASE Federrahmen. Unterhalb der Hauptdateien, die in der Spring Security/Mvc-Konfiguration und dem benutzerdefinierten AuthenticationProvider verwendet werden.

WebConfig:

@Configuration 
@EnableWebMvc 
@ComponentScan(basePackages = {"com.mypackage"}) 
@ImportResource({ "classpath:/spring-data.xml", "classpath:/trace-context.xml" }) 
@EnableTransactionManagement 
public class WebConfig extends WebMvcConfigurerAdapter { 

    @Override 
    public void addViewControllers(ViewControllerRegistry registry) { 
     registry.addViewController("/login").setViewName("login"); 
    } 

    @Bean 
    public StandardServletMultipartResolver multipartResolver() { 
     return new StandardServletMultipartResolver(); 
    } 

    @Bean(destroyMethod = "shutdown") 
    public GraphDatabaseService graphDatabaseService() { 
     return new GraphDatabaseFactory().newEmbeddedDatabase("target/temp.db"); 
    } 

    @Bean 
    public RepositoryInitializer repositoryInitializer() { 
     return new RepositoryInitializer(); 
    } 

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

    @Override 
    public void addInterceptors(InterceptorRegistry registry) { 
     LocaleChangeInterceptor localeChangeInterceptor = new   LocaleChangeInterceptor(); 
     localeChangeInterceptor.setParamName("lang"); 
     registry.addInterceptor(localeChangeInterceptor); 
    } 

    @Bean 
    public LocaleResolver localeResolver() { 
     CookieLocaleResolver cookieLocaleResolver = new CookieLocaleResolver(); 
     cookieLocaleResolver.setDefaultLocale(StringUtils.parseLocaleString("en")); 
     return cookieLocaleResolver; 
    } 

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

    @Bean 
    public MessageSource messageSource() { 
     ReloadableResourceBundleMessageSource messageSource = new ReloadableResourceBundleMessageSource(); 
     messageSource.setBasenames("classpath:messages/messages", "classpath:messages/validation"); 
     // if true, the key of the message will be displayed if the key is not 
     // found, instead of throwing a NoSuchMessageException 
     messageSource.setUseCodeAsDefaultMessage(true); 
     messageSource.setDefaultEncoding("UTF-8"); 
     // # -1 : never reload, 0 always reload 
     messageSource.setCacheSeconds(0); 
     return messageSource; 
    } 
} 

WebInitializer:

public class WebInitializer extends AbstractAnnotationConfigDispatcherServletInitializer { 

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

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

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

    @Override 
    protected Filter[] getServletFilters() { 
     CharacterEncodingFilter characterEncodingFilter = new CharacterEncodingFilter(); 
     characterEncodingFilter.setEncoding("UTF-8"); 
     return new Filter[] { characterEncodingFilter, new SiteMeshFilter()}; 
    } 

    @Override 
    public void onStartup(ServletContext servletContext) throws ServletException { 
     super.onStartup(servletContext); 
     //servletContext.addListener(new HttpSessionEventPublisher()); 
    } 
} 

WebSecurityConfig:

@Configuration 
@EnableWebSecurity 
@Order(1) 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Override 
    protected void configure(HttpSecurity http) throws Exception { 
     http 
      .authorizeRequests().anyRequest().permitAll(); 
     // .antMatchers("/", "/login").permitAll() 
     // .anyRequest().authenticated(); 
     http 
      .formLogin() 
       .defaultSuccessUrl("/hello") 
       .loginPage("/login") 
       .permitAll() 
       .and() 
      .logout() 
       .logoutUrl("/logout") 
       .permitAll(); 
     http  
      .sessionManagement() 
      .maximumSessions(1) 
      .maxSessionsPreventsLogin(true); 

    }  

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

    @Override 
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception { 
     authManagerBuilder.authenticationProvider(new ApplicationAuthenticationProvider()); 
    } 
} 

WebSecurityInitializer:

public class WebSecurityInitializer extends AbstractSecurityWebApplicationInitializer { 

} 

AuthenticationProvider:

@Component(value = "authenticationProvider") 
public class ApplicationAuthenticationProvider implements AuthenticationProvider { 

    @Autowired 
    public UserService userService; 

    public ApplicationAuthenticationProvider() {} 

    @Override 
    public Authentication authenticate(Authentication authentication) throws AuthenticationException { 
     String username = authentication.getName(); 
     String password = (String) authentication.getCredentials(); 

     User user = userService.loadUserByUsername(username); 

     if (user == null) { 
      throw new BadCredentialsException("Username not found."); 
     } 

     if (!password.equals(user.getPassword())) { 
      throw new BadCredentialsException("Wrong password."); 
     } 

     Collection<? extends GrantedAuthority> authorities = user.getAuthorities(); 

     return new UsernamePasswordAuthenticationToken(username, password, authorities); 
    } 

    @Override 
    public boolean supports(Class<?> arg0) { 
     return true; 
    } 
} 

Userservice:

@Service 
public class UserService implements UserDetailsService { 

    @Autowired 
    private UserRepository userRepository; 


    @Override 
    public User loadUserByUsername(String username) throws UsernameNotFoundException { 
     return userRepository.findByUsername(username); 
    } 
} 

Frühling eine Ausnahme wirft, während er seinen Anwendungskontext baut (während der Initialisierung der Anwendung):

[ERROR] [main 11:53:37] (FrameworkServlet.java:initServletBean:467) Context  initialization failed 
org.springframework.beans.factory.BeanCreationException: Error creating bean with name   'authenticationProvider': Injection of autowired dependencies failed; nested exception is  org.springframework.beans.factory.BeanCreationException: Could not autowire field: public  com.evidencefactory.service.UserService  com.evidencefactory.security.ApplicationAuthenticationProvider.userService; nested  exception is java.lang.IllegalArgumentException: Can not set  com.evidencefactory.service.UserService field  com.evidencefactory.security.ApplicationAuthenticationProvider.userService to  sun.proxy.$Proxy71 

Ich verstehe nicht, warum es passiert, aber wenn ich die UserDetailsService Schnittstellenimplementierung vonentferne 210 Klasse, dann startet die Anwendung erfolgreich. Wenn jedoch ApplicationAuthenticationProvider von Spring aufgerufen wird, wird die UserService nicht automatisch in es und die Anwendung löst eine NullPointerException.

java.lang.NullPointerException 
at com.evidencefactory.security.ApplicationAuthenticationProvider.authenticate(ApplicationAuthenticationProvider.java:33) 
+0

Lassen Sie uns Ihre 'UserService' Klasse sehen. –

+0

@SotiriosDelimanolis bearbeitet. – pasemes

Antwort

4

Ich habe herausgefunden, wie es funktioniert, obwohl es immer noch einige Fragen unbeantwortet gibt.

1) Ich weiß immer noch nicht, warum Spring Kontextinitialisierung fehlschlägt, wenn UserService implementiert UserDetailsService.Da ich keine Verwendung dafür sehe, da ich eine benutzerdefinierte AuthenticationProvider verwende, habe ich diese Implementierung einfach entfernt und die Dinge sind jetzt in Ordnung. Nach bestem Wissen (von dem, was ich von meiner ersten ersten Lektüre der Spring Security-Referenzdokumentation verstehen konnte) sind die Bereitstellung einer benutzerdefinierten AuthenticationProvider oder UserDetailsService Implementierung exklusive Alternativen.

2) Wie von einem der Befragten bemerkt (@Sotirios Delimanolis) Ich war ApplicatinoAuthenticationProvider von Hand Instanziieren und da es nicht bis zum Frühjahr dieses Beispiel würde nicht haben eine UserService Instanz autowired hinein verwaltet wurde. Auf dieser Grundlage änderte ich WebSecurityConfig eine autowired Instanz von ApplicationAuthenticationProvider zu bekommen, wie kann unten gesehen werden:

@Configuration 
@EnableWebSecurity 
public class WebSecurityConfig extends WebSecurityConfigurerAdapter { 

    @Autowired 
    private ApplicationAuthenticationProvider authenticationProvider; 

    @Override 
    protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception { 
     authManagerBuilder.authenticationProvider(authenticationProvider); 
    } 
} 

Das war noch nicht ausreichend, weil ApplicationAuthenticationProvider nicht in WebSecurityConfig autowired werden wurde. Basierend auf diesem Link Spring Security 3.1.3 @Autowired not Work when using WebApplicationInitializer bemerkte ich, dass dies daran lag, dass die Sicherheitskonfiguration auch eine Komponenten-Scan-Deklaration haben sollte. Das Hinzufügen von @ComponentScan(basePackages = {"com.mypackage"}) zu WebSecurityConfig löste das Problem.

3

Ich werde diesen UserService anzunehmen, ist eine Klasse und hat einige @Transactional Anmerkung entweder auf sich selbst oder eine seiner Methoden.

Sie werden CGLIB zu Ihrem Classpath hinzufügen müssen, und ändern Sie Ihre @EnableTransactionManagement zu

@EnableTransactionManagement(proxyTargetClass = true) 

so dass Spring verwendet CGLIB proxying (die Proxy-Klassen) anstelle von JKD Proxies (die nicht).


Alternativ können Sie auch eine Schnittstelle UserService und implementieren (und mit Anmerkungen versehen mit @Service) eine UserServiceImpl Klasse erstellen. Das Feld "Autoverdrahtet" UserService bleibt gleich, aber Spring kann JDK-Proxys verwenden.

+0

Die Annotation @EnableTransactionManagement (proxyTargetClass = true) wurde zur UserService-Klasse hinzugefügt. Der Fehler wurde in org.springframework.beans.factory.BeanCreationException geändert: Fehler beim Erstellen der Bean mit dem Namen 'evidenceEditorController': Die Injektion von Abhängigkeiten mit Autowired ist fehlgeschlagen; Verschachtelte Ausnahme ist org.springframework.beans.factory.BeanCreationException: Feld konnte nicht autowire: private com.evidencefactory.service.TermService com.evidencefactory.controller.EvidenceEditorController.termService; verschachtelte Ausnahme ist org.springframework.beans.factory.BeanCreationException: ... – pasemes

+0

@pasemes Die Annotation geht auf 'WebConfig', nicht' UserService'. –

+0

Dieser Fehler tritt nicht auf, wenn ich die Spring Security-Java-Konfiguration nicht verwende, d. H. Ohne die Konfigurationsklassen WebSecurityConfig und WebSecurityInitializer. Ich verstehe dieses Verhalten nicht. – pasemes