【问题标题】:spring security jdbc throws null pointerspring security jdbc抛出空指针
【发布时间】:2014-07-28 22:17:17
【问题描述】:

我正在尝试将 Spring-Security 4.0.0.M1 与 Spring-Boot 1.0.2.RELEASE 与 H2 和 Spring-data-jpa.1.5.2 一起使用。我可以在 SecurityConfig.configure 方法中创建一个用户,但是当我将它提取到它自己的类中时,我得到一个空指针异常。我进入 JdbcDaoSupport.java 并看到 getJdbcTemplate() 返回一个 null jdbcTemplate。

这是我的配置:

@Configuration
@EnableWebMvcSecurity
@EnableGlobalMethodSecurity(prePostEnabled = false)
public class SecurityConfig extends WebSecurityConfigurerAdapter { 
    @Autowired
    private DataSource dataSource;

    @Autowired
    UserService userService;

    @Override
    protected void configure(HttpSecurity http) throws Exception {

        http
                .authorizeRequests()
                .antMatchers( "/resources/**" ).permitAll()
                .antMatchers( "/css/**" ).permitAll();

        http
                .formLogin().failureUrl( "/login?error" )
                .defaultSuccessUrl( "/" )
                .loginPage( "/login" )
                .permitAll()
                .and()
                .logout().logoutRequestMatcher( new AntPathRequestMatcher( "/logout" ) ).logoutSuccessUrl( "/login" )
                .permitAll();

        http
                .authorizeRequests().anyRequest().authenticated();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .jdbcAuthentication()
                .dataSource( dataSource );
    }

    @Bean
    @Override
    public AuthenticationManager authenticationManager() throws Exception {
        return super.authenticationManagerBean();
    }
}

我的主要配置类定义了数据源,我知道它可以工作:

@Bean
public DataSource dataSource() {
    return new EmbeddedDatabaseBuilder().setType( EmbeddedDatabaseType.H2 ).setName( "ofac" )
            .addScript( "classpath:h2.sql" ).build();
}

我有一个用于添加用户的用户服务:

@Component
public class UserService {

    @Autowired
    private AuthenticationManagerBuilder authenticationManagerBuilder;

    @Autowired
    private javax.sql.DataSource dataSource;

    @PostConstruct()
    public void initUsers() throws Exception {
        addNewUser( "admin", "password", "ADMIN" );
    }

     public void addNewUser(String username, String plainPassword, String role) {

    List<GrantedAuthority> authorities = new ArrayList<GrantedAuthority>();
    authorities.add( new SimpleGrantedAuthority( role ) );
    PasswordEncoder encoder = new BCryptPasswordEncoder();

    UserDetails hashedUser = new User( username, encoder.encode( plainPassword ), authorities );

    JdbcUserDetailsManager userDetailsService = (JdbcUserDetailsManager) authenticationManagerBuilder.getDefaultUserDetailsService();
    try {
        if ( userDetailsService.userExists( hashedUser.getUsername() ) ) {
            userDetailsService.deleteUser( hashedUser.getUsername() );
        }
        // and finally, create the user
        userDetailsService.createUser( hashedUser );
    } catch ( Exception ex ) {
        ex.printStackTrace();
    }
 }
}

我在 UserService.initUsers 上有一个断点,当行:

authenticationManagerBuilder.jdbcAuthentication().getUserDetailsService().userExists( hashedUser.getUsername() ) 

被调用,我可以看到authenticationManagerBuilder.jdbcAuthentication() 返回一个空的jdbcTemplate。所有在线文档似乎都表明这会起作用,但它似乎并没有像我期望的那样连接所有东西。

有谁知道可能出了什么问题?

更新: 我更改了项目,所以我不再拥有 SecurityConfig,而是拥有一个:

@Order(SecurityProperties.ACCESS_OVERRIDE_ORDER)
@Configuration
public class ApplicationSecurity extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http
                .authorizeRequests()
                .antMatchers( "/resources/**" ).permitAll()
                .antMatchers( "/css/**" ).permitAll();

        http
                .formLogin().failureUrl( "/login?error" )
                .defaultSuccessUrl( "/" )
                .loginPage( "/login" )
                .permitAll()
                .and()
                .logout().logoutRequestMatcher( new AntPathRequestMatcher( "/logout" ) ).logoutSuccessUrl( "/login" )
                .permitAll();

        http
                .authorizeRequests().anyRequest().authenticated();
    }
}

还有一个:

@Order(Ordered.HIGHEST_PRECEDENCE)
@Configuration
public class AuthenticationSecurity extends GlobalAuthenticationConfigurerAdapter {


    @Autowired
    private DataSource dataSource;

    @Override
    public void init(AuthenticationManagerBuilder auth) throws Exception {
        auth
                .jdbcAuthentication()
                .dataSource( dataSource );
    }
}

但是在我的 UserService 中,我在这里得到了一个 null userDetailsS​​ervice:

JdbcUserDetailsManager userDetailsService = (JdbcUserDetailsManager) authenticationManagerBuilder.getDefaultUserDetailsService();

我还没有弄清楚如何在启动后实际创建用户。我认为它与 UserDetailsS​​ervice 一起使用,但它不提供该功能。我想可能需要一个 JdbcUserDetailsManager,但到目前为止,我还无法连接一个有效的方法。

【问题讨论】:

  • 我认为如果您想在两个地方共享用户详细信息服务,您应该将其定义为 bean。注入 auth mgr 构建器并不打算以这种方式工作。

标签: spring-security spring-boot


【解决方案1】:

AuthenticationManagerBuilder 在注入对象时可能尚未完全初始化。 Spring Security 使用各种标记来表示初始化顺序,例如你可以尝试像the method security sample 一样扩展GlobalAuthenticationConfigurerAdapter

【讨论】:

  • 我用建议更新了我的帖子,除了我将 ApplicaitonSecurity 和 AuthentiationSecurity 提取到他们自己的 @Configuration 文件中,因为我无法像示例那样将数据源加载到静态文件中。但是在尝试 PostConstruct 添加新用户时,我仍然得到一个空值。
  • 您答案中示例的网址已更改。对于那些从搜索引擎中找到这个的人。方法安全示例的主类的新 url 现在是:github.com/spring-projects/spring-boot/blob/master/…
猜你喜欢
  • 2014-07-25
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2012-09-30
  • 1970-01-01
  • 1970-01-01
  • 2017-06-27
  • 1970-01-01
相关资源
最近更新 更多