Spring Security中是否有一些配置或可用模块来限制登录尝试(理想情况下,我希望在后续失败尝试之间等待时间增加)?如果没有,应该使用哪个API部分?
答案 0 :(得分:14)
实现AuthenticationFailureHandler,用于更新数据库中的计数/时间。我不会指望使用会话,因为无论如何攻击者都不会发送cookie。
答案 1 :(得分:11)
从Spring 4.2开始annotation based event listeners可用:
@Component
public class AuthenticationEventListener {
@EventListener
public void authenticationFailed(AuthenticationFailureBadCredentialsEvent event) {
String username = (String) event.getAuthentication().getPrincipal();
// update the failed login count for the user
// ...
}
}
答案 2 :(得分:5)
我最近实现了一个类似的功能来监控使用JMX的登录失败。请参阅我对问题Publish JMX notifications in using Spring without NotificationPublisherAware的回答中的代码。身份验证提供程序的身份验证方法的一个方面更新MBean,并使用通知侦听器(该问题中未显示的代码)来阻止用户和IP,发送警报电子邮件,甚至在故障超过阈值时暂停登录。
修改强>
与我对问题Spring security 3 : Save informations about authentification in database的回答类似,我认为捕获身份验证失败事件(而不是自定义处理程序)并将信息存储在数据库中也将起作用,它也会使代码保持分离。
答案 3 :(得分:5)
正如Rob Winch在http://forum.springsource.org/showthread.php?108640-Login-attempts-Spring-security中所建议的那样,我只是将DaoAuthenticationProvider
(也可以使用Ritesh建议的方面完成)来限制登录失败的数量,但你也可以断言前提条件:
public class LimitingDaoAuthenticationProvider extends DaoAuthenticationProvider {
@Autowired
private UserService userService;
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
// Could assert pre-conditions here, e.g. rate-limiting
// and throw a custom AuthenticationException if necessary
try {
return super.authenticate(authentication);
} catch (BadCredentialsException e) {
// Will throw a custom exception if too many failed logins have occurred
userService.recordLoginFailure(authentication);
throw e;
}
}
}
在Spring config XML中,只需引用这个bean:
<beans id="authenticationProvider"
class="mypackage.LimitingDaoAuthenticationProvider"
p:userDetailsService-ref="userDetailsService"
p:passwordEncoder-ref="passwordEncoder"/>
<security:authentication-manager>
<security:authentication-provider ref="authenticationProvider"/>
</security:authentication-manager>
请注意,我认为可能不会使用依赖于访问AuthenticationException
的{{1}}或authentication
属性(例如实现extraInformation
)的解决方案,因为这些属性现已弃用(至少在Spring Security 3.1中)。
答案 4 :(得分:4)
您还可以使用实现ApplicationListener的服务&lt; AuthenticationFailureBadCredentialsEvent&gt;更新数据库中的记录。
参见spring应用程序事件。
答案 5 :(得分:4)
这是我的实施,希望有所帮助。
AbstractUserDetailsAuthenticationProvider
)最后,扩展DaoAuthenticationProvider,并将逻辑集成在里面。
@Component("authenticationProvider")
public class YourAuthenticationProvider extends DaoAuthenticationProvider {
@Autowired
UserAttemptsDao userAttemptsDao;
@Override
public Authentication authenticate(Authentication authentication)
throws AuthenticationException {
try {
Authentication auth = super.authenticate(authentication);
//if corrent password, reset the user_attempts
userAttemptsDao.resetFailAttempts(authentication.getName());
return auth;
} catch (BadCredentialsException e) {
//invalid login, update user_attempts, set attempts+1
userAttemptsDao.updateFailAttempts(authentication.getName());
throw e;
}
}
}
有关完整的源代码和实现,请参阅此内容 - Spring Security limit login attempts example,
答案 6 :(得分:1)
编写自定义事件侦听器
@Component("authenticationEventListner")
public class AuthenticationEventListener
implements AuthenticationEventPublisher
{
@Autowired
UserAttemptsServices userAttemptsService;
@Autowired
UserService userService;
private static final int MAX_ATTEMPTS = 3;
static final Logger logger = LoggerFactory.getLogger(AuthenticationEventListener.class);
@Override
public void publishAuthenticationSuccess(Authentication authentication) {
logger.info("User has been logged in Successfully :" +authentication.getName());
userAttemptsService.resetFailAttempts(authentication.getName());
}
@Override
public void publishAuthenticationFailure(AuthenticationException exception, Authentication authentication) {
logger.info("User Login failed :" +authentication.getName());
String username = authentication.getName().toString();
UserAttempts userAttempt = userAttemptsService.getUserAttempts(username);
User userExists = userService.findBySSO(username);
int attempts = 0;
String error = "";
String lastAttempted = "";
if (userAttempt == null) {
if(userExists !=null ){
userAttemptsService.insertFailAttempts(username); }
} else {
attempts = userAttempt.getAttempts();
lastAttempted = userAttempt.getLastModified();
userAttemptsService.updateFailAttempts(username, attempts);
if (attempts + 1 >= MAX_ATTEMPTS) {
error = "User account is locked! <br>Username : "
+ username+ "<br>Last Attempted on : " + lastAttempted;
throw new LockedException(error);
}
}
throw new BadCredentialsException("Invalid User Name and Password");
}
}
3.安全配置
1) @Autowired
@Qualifier("authenticationEventListner")
AuthenticationEventListener authenticationEventListner;
2) @Bean
public AuthenticationEventPublisher authenticationListener() {
return new AuthenticationEventListener();
}
3) @Autowired
public void
configureGlobalSecurity(AuthenticationManagerBuilder auth) throws Exception {
auth.userDetailsService(userDetailsService).passwordEncoder(passwordEncoder());
//configuring custom user details service
auth.authenticationProvider(authenticationProvider);
// configuring login success and failure event listener
auth.authenticationEventPublisher(authenticationEventListner);
}