Spring Security:抛出LockedException而不是BadCredentialsException,为什么?

Was*_*tar 7 java spring spring-security

使用Spring Security 4.0.2.RELEASE

对于使用spring-security框架的基本用户身份验证,我实现了spring-security DaoAuthenticationProvider

当用户尝试使用正确的用户名登录时,错误的密码和用户的帐户已被锁定,那么我预计spring-security身份验证模块会抛出BadCredentialsException但是它会抛出LockedException

我的问题是

  1. 为什么spring-security正在处理用户进行进一步的身份验证,而凭据特殊密码不正确?
  2. 即使用户的密码无效,在应用程序中显示"用户被锁定"的消息是否良好?
  3. 如何设置生成/捕获BadCredentialsException无效密码和锁定用户?

任何帮助,将不胜感激.身份验证提供程序实现代码

@Component("authenticationProvider")
public class LoginAuthenticationProvider extends DaoAuthenticationProvider {

    @Autowired
    UserDAO userDAO;

    @Autowired
    @Qualifier("userDetailsService")
    @Override
    public void setUserDetailsService(UserDetailsService userDetailsService) {
        super.setUserDetailsService(userDetailsService);
    }

    @Override
    public Authentication authenticate(Authentication authentication) throws AuthenticationException {
        try {
            Authentication auth = super.authenticate(authentication);
            // if reach here, means login success, else exception will be thrown

            // reset the user attempts
            userDAO.resetPasswordRetryAttempts(authentication.getName());

            return auth;
        } catch (BadCredentialsException ex) {
            // invalid login, update user attempts
            userDAO.updatePasswordRetryAttempts(authentication.getName(), PropertyUtils.getLoginAttemptsLimit());
            throw ex;
        } catch (LockedException ex) {
            // this user is locked
            throw ex;
        } catch (AccountExpiredException ex) {
            // this user is expired
            throw ex;
        } catch (Exception ex) {
            ex.printStackTrace();
            throw ex;
        }
    }

}
Run Code Online (Sandbox Code Playgroud)

Ral*_*lph 7

您问:

Spring Security:抛出LockedException而不是BadCredentialsException,为什么?

这是因为Spring Security将首先检查该帐户是否存在并有效,然后再检查密码。

更具体:在中完成AbstractUserDetailsAuthenticationProvider.authenticate。在非常简短的说明中,该方法以这种方式工作:

user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
...
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
...
postAuthenticationChecks.check(user);
Run Code Online (Sandbox Code Playgroud)
  • retrieveUser -加载用户
  • preAuthenticationChecks.check(user);- DefaultPreAuthenticationChecks:检查是否已锁定...
  • additionalAuthenticationChecks -检查密码
  • postAuthenticationChecks.check(user);- DefaultPostAuthenticationChecks检查未过期的凭证

好处是,preAuthenticationChecks并且postAuthenticationChecks是接口的引用,UserDetailsChecker因此您可以更改它们。只需实现自己的两个UserDetailsChecker,一个用于pre的Null-Implementation,一个用于检查所有内容的post:

  • !user.isAccountNonLocked()
  • !user.isEnabled()
  • !user.isAccountNonExpired()
  • !user.isCredentialsNonExpired()