在几个博客文章和SO问题中相对较好地讨论了这个问题.然而,我无法找到一个专门解决java配置问题的人.我怀疑我在java配置文件中做错了,因为我发现一些帖子表明可以通过删除调试XML标签来解决问题(https://jira.springsource.org/browse/ SEC-1885).
我正在使用Spring安全性的3.2.0.RELEASE和Spring框架的3.2.6.RELEASE.在spring security/mvc配置和自定义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在构建应用程序上下文时(在应用程序初始化期间)抛出异常:
[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
我不明白它为什么会发生,但如果我UserDetailsService
从UserService
类中删除接口实现,那么应用程序就会成功启动.但是,当ApplicationAuthenticationProvider
Spring调用时,UserService
它不会自动装入它,并且应用程序抛出NullPointerException.
java.lang.NullPointerException at com.evidencefactory.security.ApplicationAuthenticationProvider.authenticate(ApplicationAuthenticationProvider.java:33)
pasemes.. 5
弄清楚如何将其付诸实施,尽管仍有一些问题没有得到解决.
1)我仍然不知道UserService
实现时Spring上下文初始化失败的原因UserDetailsService
.鉴于我没有看到它的使用,因为我正在使用自定义AuthenticationProvider
,我刚刚删除了这个实现,现在一切正常.据我所知(从我第一次初读Spring Security参考文档时可以理解)提供自定义AuthenticationProvider
或UserDetailsService
实现是唯一的选择.
2)正如其中一位受访者(@Sotirios Delimanolis)所注意到的那样,我ApplicatinoAuthenticationProvider
手动实例化,因为它不是由Spring管理的,所以这个实例不会有UserService
自动装入它的实例.基于此,我改为WebSecurityConfig
获得一个自动装配的实例,ApplicationAuthenticationProvider
如下所示:
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private ApplicationAuthenticationProvider authenticationProvider; @Override protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception { authManagerBuilder.authenticationProvider(authenticationProvider); } }
这还不够,因为ApplicationAuthenticationProvider
没有自动装入WebSecurityConfig
.基于此链接Spring Security 3.1.3 @Autowired not Work在使用WebApplicationInitializer时我注意到这是因为安全配置也应该有组件扫描声明.添加@ComponentScan(basePackages = {"com.mypackage"})
到WebSecurityConfig
解决这个问题.
弄清楚如何将其付诸实施,尽管仍有一些问题没有得到解决.
1)我仍然不知道UserService
实现时Spring上下文初始化失败的原因UserDetailsService
.鉴于我没有看到它的使用,因为我正在使用自定义AuthenticationProvider
,我刚刚删除了这个实现,现在一切正常.据我所知(从我第一次初读Spring Security参考文档时可以理解)提供自定义AuthenticationProvider
或UserDetailsService
实现是唯一的选择.
2)正如其中一位受访者(@Sotirios Delimanolis)所注意到的那样,我ApplicatinoAuthenticationProvider
手动实例化,因为它不是由Spring管理的,所以这个实例不会有UserService
自动装入它的实例.基于此,我改为WebSecurityConfig
获得一个自动装配的实例,ApplicationAuthenticationProvider
如下所示:
@Configuration @EnableWebSecurity public class WebSecurityConfig extends WebSecurityConfigurerAdapter { @Autowired private ApplicationAuthenticationProvider authenticationProvider; @Override protected void configure(AuthenticationManagerBuilder authManagerBuilder) throws Exception { authManagerBuilder.authenticationProvider(authenticationProvider); } }
这还不够,因为ApplicationAuthenticationProvider
没有自动装入WebSecurityConfig
.基于此链接Spring Security 3.1.3 @Autowired not Work在使用WebApplicationInitializer时我注意到这是因为安全配置也应该有组件扫描声明.添加@ComponentScan(basePackages = {"com.mypackage"})
到WebSecurityConfig
解决这个问题.