Spring Security,Boot:替换默认的DaoAuthenticationProvider

时间:2015-06-14 23:39:36

标签: java spring security spring-mvc spring-boot

我正在尝试在登录过程中添加用户ip验证。如果用户的IP地址不在数据库中,则应用程序应拒绝身份验证。

问题:鉴于下面的设置,结果是auth.authenticationProvider()没有替换默认的DaoAuthenticationProvider,而是将UserIpAuthenticationProvider添加为列表中的第一个AuthenticationProvider。

在用户名/密码组合不正确的情况下,框架最终调用UserDetailsS​​ervice.loadUserByUsername()两次,一次来自UserIpAuthenticationProvider,另一次来自内部DaoAuthenticationProvider,它抛出最终的BadCredentialsException()。

问题:是否有任何设置可以在Spring Boot中设置,以便Spring Security不会添加它自己的内部实例DaoAuthenticationProvider,而只使用我的UserIpAuthenticationProvider,它已经有了所有必要的功能(可能以某种方式替换AuthenticationManagerBuilder以覆盖userDetailsS​​ervice()方法?)。

public <T extends UserDetailsService> DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T> userDetailsService(
        T userDetailsService) throws Exception {
    this.defaultUserDetailsService = userDetailsService;
    return apply(new DaoAuthenticationConfigurer<AuthenticationManagerBuilder,T>(userDetailsService));
}

配置:根据我的理解,UserDetailsS​​ervice应该提供有关用户的所有必要详细信息,以便AuthenticationProvider可以决定身份验证是否成功。

由于从数据库加载了所有必要的信息,因此扩展DaoAuthenticationProvider并在覆盖additionalAuthenticationChecks()方法中添加额外的验证似乎很自然(白名单中的IP列表在数据库中,因此它们作为一部分加载IpAwareUser中的用户对象。

@Named
@Component
class UserIpAuthenticationProvider  extends DaoAuthenticationProvider {
    @Inject
    public UserIpAuthenticationProvider(UserDetailsService userDetailsService)
    {
        ...
    }

    @SuppressWarnings("deprecation")
    protected void additionalAuthenticationChecks(UserDetails userDetails,
                                                  UsernamePasswordAuthenticationToken authentication) throws AuthenticationException {
        super.additionalAuthenticationChecks(userDetails, authentication);

        WebAuthenticationDetails details = (WebAuthenticationDetails) authentication.getDetails();
        IpAwareUser ipAwareUser = (IpAwareUser) userDetails;
        if (!ipAwareUser.isAllowedIp(details.getRemoteAddress()))
        {
            throw new DisabledException("Login restricted from ip: " + details.getRemoteAddress());
        }
    }
}

这是注入SecurityConfiguration:

@Configuration
@EnableGlobalMethodSecurity(prePostEnabled = true)
@EnableWebSecurity
public class SecurityConfiguration extends WebSecurityConfigurerAdapter {

    @Override
    protected void configure(HttpSecurity http) throws Exception {
        http.addFilter(authenticationFilter);

        http.authorizeRequests()
                .antMatchers("/", "/javascript/**", "/css/**").permitAll()
                .antMatchers("...").access("...")
                .anyRequest().authenticated()
                .and().formLogin().loginPage("/").permitAll()
                .and().logout().invalidateHttpSession(true).deleteCookies("JSESSIONID").permitAll()
                .and().csrf().disable()
        ;
    }

    @Inject
    private UserDetailsService userDetailsService;

    @Inject
    private UserIpAuthenticationProvider userIpAuthenticationProvider;


    @Inject
    private JsonUsernamePasswordAuthenticationFilter authenticationFilter;

    @Bean
    public JsonUsernamePasswordAuthenticationFilter authenticationFilter() {
        return new JsonUsernamePasswordAuthenticationFilter();
    }

    @Override
    protected void configure(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(userIpAuthenticationProvider);
        auth.userDetailsService(userDetailsService);
    }

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

    @Bean
    public AuthenticationSuccessHandler authenticationSuccessHandler() throws Exception {
        return new JsonAuthenticationSuccessHandler();
    }

    @Bean
    public AuthenticationFailureHandler authenticationFailureHandler() throws Exception {
        return new JsonAuthenticationFailureHandler();
    }
}

和应用程序配置:

@Configuration
@EnableAutoConfiguration
@ComponentScan(basePackageClasses = {SecurityConfiguration.class, DataController.class, DaoService.class})
public class Application extends SpringBootServletInitializer {

    @Override
    protected SpringApplicationBuilder configure(SpringApplicationBuilder application) {
        return application;
    }
}

对此的任何指导都将非常感激。

2 个答案:

答案 0 :(得分:0)

定义自己的DaoAuthenticationProvider

@Bean
public DaoAuthenticationProvider daoAuthenticationProvider() {
    return new UserIpAuthenticationProvider();
}

应该替换Spring Boot默认实例(不是Bean类型是DaoAuthenticationProvider,而不是 UserIpAuthenticationProvider)

答案 1 :(得分:0)

对问题的评论包含答案:

<块引用>

@ArunM:你的项目给了我一个想法:我不需要调用 auth.userDetailsS​​ervice(userDetailsS​​ervice);在 SecurityConfiguration.configure() 中,这将阻止创建内部 DaoAuthenticationProvider!我的 UserIpAuthenticationProvider 可以通过注入获取 UserDetailsS​​ervice 的实例。

AuthenticationManagerBuilder.userDetailsService 方法不仅设置默认的 UserDetailsService,还应用注册 DaoAuthenticationConfigurerDaoAuthenticationProvider

如果您想要自定义的 DaoAuthenticationProvider,请将 UserDetailsService 传递给构造函数中的提供程序或注入它。并且为了防止默认的 DaoAuthenticationProvider 被注册,请不要调用 AuthenticationManagerBuilder.userDetailsService

Spring Security issue中也提到了这一点。