spring security authenticationProvider用法及关闭不隐藏UserNotFoundException的解决

10 篇文章 1 订阅

这两天采用了spring security做登录验证,上一篇说到了增加图形验证码的解决办法,我们在config中增加了一个authenticationProvider的实现类。接下来我遇到的问题是用户登录失败(用户不存在或密码错误)之后,security框架直接返回的是验证失败。而我的需求是将用户不存在和密码错误区分开来,然后做不同的后续工作。

出现这个问题的配置是:

……
 @Inject
    public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
        auth.authenticationProvider(customAuthenticationProvider)
            .userDetailsService(userDetailsService)
                .passwordEncoder(passwordEncoder());

    }
……

因发现UserNotFoundException异常是在DaoAuthenticationProvider中被屏蔽掉的,而DaoAuthenticationProvider中有个属性hideUserNotFoundExceptions,默认是ture,也就是说要想抛出UserNotFoundException,需要把hideUserNotFoundExceptions设为false。
于是增加了一个DaoAuthenticationProvider的配置

@Bean
public DaoAuthenticationProvider authenticationProvider() {
    DaoAuthenticationProvider provider = new DaoAuthenticationProvider();
    provider.setHideUserNotFoundExceptions(false);
    provider.setUserDetailsService(userDetailsService);
    provider.setPasswordEncoder(passwordEncoder());
    return provider;
}
@Inject
public void configureGlobal(AuthenticationManagerBuilder auth) throws Exception {
    auth.authenticationProvider(customAuthenticationProvider)
        .authenticationProvider(authenticationProvider()) //增加
        .userDetailsService(userDetailsService)
        .passwordEncoder(passwordEncoder());
}

出现的结果是调用了两次userDetailsService中的验证,UserNotFoundException还是被屏蔽掉了。
经过源码跟踪,发现了ProviderManager这个类,这个类中有这么一段代码:

……
for (AuthenticationProvider provider : getProviders()) {
    if (!provider.supports(toTest)) {
        continue;
    }
    if (debug) {
        logger.debug("Authentication attempt using "
                + provider.getClass().getName());
    }

    try {
        result = provider.authenticate(authentication);

        if (result != null) {
            copyDetails(authentication, result);
            break;
        }
    }
    catch (AccountStatusException e) {
        prepareException(e, authentication);
        throw e;
    }
    catch (InternalAuthenticationServiceException e) {
        prepareException(e, authentication);
        throw e;
    }
    catch (AuthenticationException e) {
        lastException = e;
    }
}
……

从上边的代码可以看出,对于AuthenticationProvider,只要配置几个provider,就会执行几个,但我在config中只配了两个,为什么会执行三个呢?
最后发现原因在于

auth .userDetailsService(userDetailsService)
        .passwordEncoder(passwordEncoder());

这两个会默认在providerlist中增加一个DaoAuthenticationProvider,看到这里果断将这两行注释掉。再次测试,完美通过。UserNotFoundException也抛出来了

下面总结下authenticationProvider:
1、验证过程中,可以增加多个authenticationProvider,来完成不同的验证工作
2、根据验证的先后顺序,需要注意authenticationProvider设置的先后顺序。
3、如果抛出异常,即可停止的话,不能抛出AuthenticationException
4、每个authenticationProvider都要配置一个UserDetailsService的实现类
5、如果不使用DaoAuthenticationProvider或要重新配置,就直接使用auth.authenticationProvider()方法,不要使用auth .userDetailsService()

  • 11
    点赞
  • 24
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值