Spring Security 3.2: @Autowire funktioniert nicht mit java Konfiguration und custom-AuthenticationProvider in Spring MVC Anwendung?
Dieses problem ist relativ gut diskutiert in mehreren blog-posts und SO Fragen. Dennoch, ich war nicht in der Lage, einen zu finden, die ganz spezifisch auf das problem mit der java-Konfiguration. Ich bin zu Ahnen, dass ich was falsch mache in meinem java-Konfigurationsdateien, denn ich habe festgestellt, dass einige Beiträge, die angibt, dass das problem gelöst werden kann durch das entfernen der debug-XML-tag (https://jira.springsource.org/browse/SEC-1885).
Ich bin mit der 3.2.0.RELEASE von spring security, und 3.2.6.RELEASE des spring-Frameworks. Nachfolgend die wichtigsten Dateien verwendet das spring security - /mvc-Konfiguration und custom-AuthenticationProvider.
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);
}
}
Spring wirft eine Ausnahme aus, während baut seine application-Kontext (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 ist, aber wenn ich entfernen Sie die UserDetailsService
- Schnittstelle-Implementierung von UserService
Klasse, dann wird die Anwendung erfolgreich gestartet wurde. Allerdings, wenn ApplicationAuthenticationProvider
ist aufgerufen, bis zum Frühjahr, die UserService
ist nicht autowired in es und die Anwendung löst eine NullPointerException.
java.lang.NullPointerException
at com.evidencefactory.security.ApplicationAuthenticationProvider.authenticate(ApplicationAuthenticationProvider.java:33)
UserService
Klasse.bearbeitet.
InformationsquelleAutor pasemes | 2013-12-24
Du musst angemeldet sein, um einen Kommentar abzugeben.
Herausgefunden, wie es funktioniert, obwohl es immer noch einige Fragen unbeantwortet.
1) ich weiß immer noch nicht, warum der Frühling Kontext-Initialisierung schlägt fehl, wenn
UserService
implementiertUserDetailsService
. Da ich nicht sehe, Verwendung für Sie, da bin ich mit einer benutzerdefiniertenAuthenticationProvider
ich nur entfernt diese Implementierung und die Sachen sind ok für jetzt.Nach meinem besten wissen (von dem, was ich verstehen konnte aus meiner ersten Lektüre von Spring Security Referenz-Dokumentation) bereitstellen einer benutzerdefinierten
AuthenticationProvider
oder eineUserDetailsService
Umsetzung sind exklusive alternativen.2) Wie bemerkt, von einer der Befragten (@Sotirios Delimanolis) ich war instanziieren
ApplicatinoAuthenticationProvider
per hand und da war es nicht verwaltete Frühjahr dieses Beispiel würde nicht haben eineUserService
Instanz autowired in es. Auf dieser Grundlage änderte ichWebSecurityConfig
um eine autowired InstanzApplicationAuthenticationProvider
wie kann unten gesehen werden:War dies noch nicht ausreichend, da
ApplicationAuthenticationProvider
war nicht autowired inWebSecurityConfig
. Basierend auf diesem link Spring Security 3.1.3 @Autowired nicht die Arbeit, wenn Sie WebApplicationInitializer bemerkte ich, dass dies war, weil die Sicherheit config sollte eine Komponente scan-Erklärung zu. Hinzufügen@ComponentScan(basePackages = {"com.mypackage"})
zuWebSecurityConfig
ist das problem gelöst.InformationsquelleAutor pasemes
Gehe ich davon aus, dass
UserService
ist eine Klasse und hat einige@Transactional
annotation entweder auf sich selbst oder eine seiner Methoden.Müssen Sie CGLIB Ihren Klassenpfad ein und ändern Sie Ihre
@EnableTransactionManagement
zuso, dass der Frühling verwendet CGLIB-proxying (die proxy-Klassen) anstelle von JKD-Proxys (die nicht).
Alternativ können Sie erstellen eine Schnittstelle
UserService
und umzusetzen (und kommentieren mit@Service
)UserServiceImpl
Klasse. Ihre autowiredUserService
Bereich würde die gleiche bleiben, aber der Frühling wird in der Lage sein zu verwenden JDK-proxies.Die Anmerkung geht auf
WebConfig
, nichtUserService
.Dieser Fehler tritt nicht auf, wenn ich nicht verwenden, das Spring Security-java-Konfiguration, d.h., ohne die WebSecurityConfig und WebSecurityInitializer config-Klassen. Ich bin nicht zu verstehen, dieses Verhalten.
Ich kann nicht finden, die genaue Ursache jetzt, aber der Grund ist, dass einige Bohnen verursacht Frühjahr um einen proxy für Ihre Bohnen. Es verwendet den JDK-proxies, die nicht proxy-Klassen. Es ist nicht die Transaktion Verwaltung von Proxys schließlich.
Sorry für die mangelnde Aufmerksamkeit. Hinzugefügt @EnableTransactionManagement(proxyTargetClass = true) Anmerkung zu den beiden-Klassen-Konfiguration über WebConfig und WebSecurityConfig. Wenn ich es verstanden habe correlctly, der Fehler jetzt ist, der angibt, dass der Frühling ist nicht in der Lage, @Autowire private Mitglieder. Ist, dass das gewünschte Verhalten?
InformationsquelleAutor Sotirios Delimanolis