在我花了一天时间调试和审查下面描述的问题的所有现有线程后,我想我会联系专家。虽然主题上有很多主题,但答案要么对我不起作用,要么特定于XML配置,所以我决定发布配置细节以查看我的错误。我的整个spring配置是Java Config,因此没有其他与Spring相关的XML文件。
问题: 实现Spring Security UserDetailsService的自定义服务的自动装配在自定义身份验证提供程序中不起作用。当我尝试访问服务时,它会抛出空指针异常(NPE)。我在SecurityConfig上有必要的注释来扫描包,也在Root上下文中,但这不能解决问题。启动时没有错误,但是在访问失败时会失败。
我已经审核并遵循了许多主题中的建议,但这些似乎非常相关且直接相关
spring-security-3-2-autowire-doesnt-work-with-java-configuration
autowire-is-not-working-in-spring-security-custom-authentication-provider
任何人的帮助都会非常感激。
Spring版本:
<!-- Spring -->
<spring-framework.version>4.1.2.RELEASE</spring-framework.version>
<spring-security-web.version>3.2.5.RELEASE</spring-security-web.version>
<spring-security-config.version>3.2.5.RELEASE</spring-security-config.version>
<spring-security-tags.version>3.2.5.RELEASE</spring-security-tags.version>
运行时环境: 我已经在Tomcat8和WLS 12.1.3上进行了测试,得到了相同的结果。
Spring Security Java配置:
@Configuration
@EnableWebMvcSecurity
@ComponentScan(basePackages={"com.drajer.cen.*"})
public class WebtoolSecurityConfig extends WebSecurityConfigurerAdapter {
@Autowired
public void registerGlobalAuthentication(
AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(new WebtoolAuthenticationProvider());
}
@Override
protected void configure(HttpSecurity http) throws Exception {
http
.authorizeRequests()
.antMatchers("/").permitAll()
.anyRequest().authenticated()
.and()
.formLogin()
.permitAll()
.and()
.logout()
.permitAll();
}
}
自定义身份验证提供程序类
@Component
public class WebtoolAuthenticationProvider implements AuthenticationProvider {
@Autowired
UserDetailsService userDetailsDao;
/* (non-Javadoc)
* @see org.springframework.security.authentication.AuthenticationProvider#authenticate(org.springframework.security.core.Authentication)
*/
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
String name = authentication.getName();
String password = authentication.getCredentials().toString();
System.out.println("*** IN THE METHOD *** UN: " + name + " PWD: " + password);
// use the credentials to try to authenticate against the third party system
if (authenticationSuccessful(authentication)) {
System.out.println(" Create session object");
// Populate the list of grants
List<GrantedAuthority> grantedAuths = new ArrayList<>();
UserSessionInfo us = userDetailsDao.loadUserByUsername(name);
Authentication auth = new UsernamePasswordAuthenticationToken(us, password, grantedAuths);
return auth;
} else {
throw new SecurityException("Unable to auth against Directory for user " + name);
}
}
@Override
public boolean supports(Class<?> authentication) {
return authentication.equals(UsernamePasswordAuthenticationToken.class);
}
public boolean authenticationSuccessful(Authentication authentication){
boolean authSuccessful = false;
LdapAuthenticationProvider prov = WebtoolLdapConfiguration.getLdapAuthenticationProvider();
try
{
Authentication result = prov.authenticate(authentication);
if(result != null )
{
System.out.println("Auth Successful for user ");
authSuccessful = true;
}
}
catch(AuthenticationException e)
{
System.out.println("Caught Exception, unable to authenticate user ");
}
return authSuccessful;
}
}
Null Pointer Exception发生在我访问userDetailsDao以获取authenticate方法中的UserSessionInfo对象的行上。如果依赖项已正确自动装配,则不会发生这种情况。
用户详细信息服务自定义实施
@Service
@Transactional
public class WebtoolSecurityServicesImpl implements UserDetailsService {
@Autowired
UserDao dao;
@Override
public UserDetails loadUserByUsername(String userId)
throws UsernameNotFoundException {
System.out.println("*******************This method is being called , User Id = " + userId);
return dao.getUserSessionInfo(userId);
}
}
Application Root Config class
@Configuration // Default Root config,
@ComponentScan({"com.drajer.cen.*"})
public class WebtoolRootConfiguration {
}
MvcConfiguration
@Configuration
// @EnableMvc not required due to DelegatingWebMvcConfiguration
@ComponentScan({"com.drajer.cen.*"})
@EnableTransactionManagement
@Order(1)
public class WebtoolWebMvcConfiguration extends
DelegatingWebMvcConfiguration {
@Bean
public SessionFactory sessionFactory() {
LocalSessionFactoryBuilder builder =
new LocalSessionFactoryBuilder(dataSource());
builder.scanPackages("com.drajer.cen.*")
.addResource("database/hibernate.cfg.xml")
.addResource("database/queries.xml")
.addProperties(getHibernateProperties());
SessionFactory sf = builder.buildSessionFactory();
return sf;
}
private Properties getHibernateProperties() {
Properties prop = new Properties();
prop.put("hibernate.format_sql", "true");
prop.put("hibernate.show_sql", "true");
prop.put("hibernate.dialect",
"org.hibernate.dialect.Oracle10gDialect");
return prop;
}
@Bean(name = "dataSource")
public BasicDataSource dataSource() {
BasicDataSource ds = new BasicDataSource();
ds.setDriverClassName("oracle.jdbc.driver.OracleDriver");
ds.setUrl("jdbc:oracle:thin:@localhost:1521/XE");
ds.setUsername("webtool");
ds.setPassword("webtool");
ds.setTestOnBorrow(true);
ds.setValidationQuery("SELECT 1 FROM DUAL");
return ds;
}
//Create a transaction manager
@Bean
public HibernateTransactionManager txManager() {
return new HibernateTransactionManager(sessionFactory());
}
@Override
public void configureMessageConverters(List<HttpMessageConverter<?>>
converters) {
super.configureMessageConverters(converters);
Hibernate4Module hibernateModule = new Hibernate4Module();
ObjectMapper objectMapper = new ObjectMapper();
objectMapper.registerModule(hibernateModule);
MappingJackson2HttpMessageConverter jacksonHttpMessageConverter = new MappingJackson2HttpMessageConverter();
jacksonHttpMessageConverter.setObjectMapper(objectMapper);
converters.add(jacksonHttpMessageConverter);
}
}
应用程序初始化程序
public class WebtoolApplicationConfiguration implements
WebApplicationInitializer {
@Override
public void onStartup(ServletContext container) {
// Create the 'root' Spring application context
AnnotationConfigWebApplicationContext rootContext = new AnnotationConfigWebApplicationContext();
rootContext.register(WebtoolRootConfiguration.class, WebtoolSecurityConfig.class);
// Manage the lifecycle of the root application context
container.addListener(new ContextLoaderListener(rootContext));
//Adding the security filter chain to avoid WLS 12.1.3 loading issues related to Initilizers
Filter dsf = new DelegatingFilterProxy("springSecurityFilterChain");
container.addFilter("springSecurityFilterChain", dsf).addMappingForUrlPatterns(null, false, "/*");
AnnotationConfigWebApplicationContext dispatcherServlet = new AnnotationConfigWebApplicationContext();
dispatcherServlet.register(WebtoolWebMvcConfiguration.class);
// dispatcherServlet.register(WebtoolSecurityWebConfguration.class);
ServletRegistration.Dynamic registration = container.addServlet("dispatcher", new DispatcherServlet(dispatcherServlet));
registration.setLoadOnStartup(1);
registration.addMapping("/");
}
}
Servlet初始化程序:此配置(以下代码)当前未在我的配置中使用,因为它在WLS 12上不起作用,但仅适用于Tomcat 7/8。因此,配置直接加载到上面的Application Initializer中。问题与SpringSecurityFilterChain初始化有关,这不再是上述配置的问题。
/*
public class WebtoolServletConfiguration extends AbstractAnnotationConfigDispatcherServletInitializer {
@Override
protected Class<?>[] getRootConfigClasses() {
return new Class[] {WebtoolRootConfiguration.class, WebtoolSecurityConfig.class};
}
@Override
protected Class<?>[] getServletConfigClasses() {
return new Class[] {WebtoolWebMvcConfiguration.class };
}
@Override
protected String[] getServletMappings() {
return new String[] { "/" };
}
}
*/
答案 0 :(得分:1)
问题是您使用WebtoolAuthenticationProvider
创建了new
的新实例。 Autowire当时没有工作。
调整WebtoolSecurityConfig
:
@Autowired
private WebtoolAuthenticationProvider authenticationProvider;
@Autowired
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
auth.authenticationProvider(authenticationProvider);
}