【发布时间】:2015-01-24 01:53:07
【问题描述】:
在我花了一天的时间调试并审查了关于下述问题的所有现有线程后,我想我会联系专家。虽然这个主题有很多线程,但答案要么对我不起作用,要么是特定于 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-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;
}
}
空指针异常发生在我访问 userDetailsDao 以在身份验证方法中获取 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);
}
}
应用根配置类
@Configuration // Default Root config,
@ComponentScan({"com.drajer.cen.*"})
public class WebtoolRootConfiguration {
}
Mvc配置
@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 Initializer:这个(下面的代码)目前没有在我的配置中使用,因为它不能在 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[] { "/" };
}
}
*/
【问题讨论】:
标签: spring-security spring-java-config