自动装配服务在 Spring 安全 Java 配置自定义 Auth 提供程序中不起作用

Autowiring of Services not working in Spring Security Java config Custom Auth provider

在我花了一天的时间调试和审查关于下面描述的问题的所有现有线程之后,我想我应该联系专家。虽然有很多关于该主题的话题,但答案要么对我不起作用,要么特定于 XML 配置,因此我决定 post 配置详细信息以查看我哪里出错了。我的整个spring配置是Java配置,所以没有其他XML文件与Spring相关。

问题: 实现 Spring 安全 UserDetailsS​​ervice 的自定义服务的自动装配在自定义身份验证提供程序中不工作。当我尝试访问该服务时,它会抛出空指针异常 (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 安全性 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();        
}
}

自定义身份验证提供程序Class

@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 对象的行上 method.This 如果依赖项已正确自动装配,则不会发生。

用户详细信息服务自定义实现

@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);
}

}

应用程序根配置class

@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[] { "/" };
}

}
*/

问题是您使用 new 创建了 WebtoolAuthenticationProvider 的新实例。 Autowire 不工作。

调整你的WebtoolSecurityConfig

@Autowired
private WebtoolAuthenticationProvider authenticationProvider;

@Autowired
public void registerGlobalAuthentication(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(authenticationProvider);
}