使用Spring Security 4.0.2.RELEASE
对于使用spring-security框架进行基本用户身份验证,我实现了spring-security的DaoAuthenticationProvider
当用户尝试使用正确的用户名,错误的密码和用户的账户已被锁定时,我期望spring-security身份验证模块会抛出BadCredentialsException
,但它抛出的是LockedException
我的问题是:
- 为什么spring-security在凭证(尤其是密码)不正确的情况下仍然处理用户进行进一步的身份验证?
- 即使用户的密码无效,是否在应用程序中显示消息“用户已被锁定”是好的做法?
- 如何处理生成/捕获无效密码和已锁定用户的
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);
// 如果成功登录,就会到达这里,否则会抛出异常
// 重置用户尝试次数
userDAO.resetPasswordRetryAttempts(authentication.getName());
return auth;
} catch (BadCredentialsException ex) {
// 无效的登录,更新用户尝试次数
userDAO.updatePasswordRetryAttempts(authentication.getName(), PropertyUtils.getLoginAttemptsLimit());
throw ex;
} catch (LockedException ex) {
// 该用户被锁定
throw ex;
} catch (AccountExpiredException ex) {
// 该用户已过期
throw ex;
} catch (Exception ex) {
ex.printStackTrace();
throw ex;
}
}
}
你的问题是:
这是因为Spring Security首先会检查账户是否存在且有效,然后再检查密码。
更具体地说,这是在
AbstractUserDetailsAuthenticationProvider.authenticate
方法中完成的。这个方法的工作方式可以简要描述如下:retrieveUser
- 加载用户preAuthenticationChecks.check(user);
-DefaultPreAuthenticationChecks
:检查是否被锁定...additionalAuthenticationChecks
- 检查密码postAuthenticationChecks.check(user);
-DefaultPostAuthenticationChecks
:检查凭证是否过期好处是,
preAuthenticationChecks
和postAuthenticationChecks
是对UserDetailsChecker
接口的引用,所以你可以进行更改。只需实现自己的两个UserDetailsChecker
,一个是预检查的空实现,一个是后检查的实现,检查所有内容:!user.isAccountNonLocked()
!user.isEnabled()
!user.isAccountNonExpired()
!user.isCredentialsNonExpired()