草庐IT

java - Spring Security : LockedException is thrown instead of BadCredentialsException, 为什么?

coder 2024-03-19 原文

Using Spring Security 4.0.2.RELEASE

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

当用户尝试使用正确的用户名、不正确 密码登录并且用户的帐户已被锁定 时,我预计 spring-security 身份验证模块将抛出 BadCredentialsException 但它会抛出 LockedException

我的问题是

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

如有任何帮助,我们将不胜感激。 Authentication Provider 实现代码为

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

}

最佳答案

你问:

Spring Security : LockedException is thrown instead of BadCredentialsException, why?

因为spring security会先检查账号是否存在和有效,然后再检查密码。

更具体:在 AbstractUserDetailsAuthenticationProvider.authenticate 中完成。在非常简短的描述中,该方法是这样工作的:

user = retrieveUser(username, (UsernamePasswordAuthenticationToken) authentication);
...
preAuthenticationChecks.check(user);
additionalAuthenticationChecks(user, (UsernamePasswordAuthenticationToken) authentication);
...
postAuthenticationChecks.check(user);
  • retrieveUser - 加载用户
  • preAuthenticationChecks.check(user); - DefaultPreAuthenticationChecks:检查锁定...
  • additionalAuthenticationChecks - 检查密码
  • postAuthenticationChecks.check(user); - DefaultPostAuthenticationChecks 检查未过期的凭据

好的一点是,preAuthenticationCheckspostAuthenticationChecks 是对接口(interface) UserDetailsChecker 的引用,因此您可以更改它们。只需实现您自己的两个 UserDetailsChecker,一个用于 pre 的空实现,一个用于检查所有内容的 post:

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

关于java - Spring Security : LockedException is thrown instead of BadCredentialsException, 为什么?,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33969890/

有关java - Spring Security : LockedException is thrown instead of BadCredentialsException, 为什么?的更多相关文章

随机推荐