はじめに
夏も近いと思わせるような木々の緑や山の風と、いつも同じ場所から聞こえるウグイスの鳴き声で頑張れそうな気がする日々です。
動作環境
Spring Boot 2.7.3
Java SE11
Spring Security 5.6.5
実装しようとしたこと
パスワードの試行回数を制限するというのがテーマです。
正しい実装方法ではないと思います。というのも、UserのAccountNonLockedを十分に使用できておらず、コードをAuthenticationProvider、Controllerに記載しなくてはならないからです。なので、仮の実装とします。
試行した回数を記録する countOfLoginAttemptと試行した時間を記録するfirstAttemptLoginTimeを準備し認証時にアカウントをロックするか決めるというものです。
認証時に
//パスワード試行回数が10分以内に5回を超えて失敗したらアカウントロックする
Date now = new Date();
//初回ログイン時
if(user.getFirstAttemptLoginTime()==null) {
user.setFirstAttemptLoginTime(now);
}
//制限される時間を作成
Calendar addRestrictTime = Calendar.getInstance();
addRestrictTime.setTime(user.getFirstAttemptLoginTime());
addRestrictTime.add(Calendar.MINUTE, 10);
Date RestrictTime = addRestrictTime.getTime();
//ログイン試行5回以上で10分経過ならカウントは0となる。
if(user.getCountOfLoginAttempt() > 4 && now.after(RestrictTime)) {
user.setCountOfLoginAttempt(0);
user.setFirstAttemptLoginTime(now);
}
//アカウントロック
if(user.getCountOfLoginAttempt() > 4) {
if(now.before(RestrictTime)) {
throw new LockedException("It will unlocked 10 minutes after you first try to login");
}
throw new LockedException("your account is locked , please wait 10 minutes");
}
//ログインのカウントをする
user.setCountOfLoginAttempt(user.getCountOfLoginAttempt()+1);
siteUserRepository.save(user);
次に、例外をセッションに設定する。failureHandlerを使用する。
@Component
public class CustomAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler{
@Override
public void onAuthenticationFailure(HttpServletRequest request,HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException {
setDefaultFailureUrl("/login?error=true");
super.onAuthenticationFailure(request, response, exception);
System.out.println(exception.getMessage());
request.getSession().setAttribute(WebAttributes.AUTHENTICATION_EXCEPTION, exception.getMessage());
}
}
configにも設定が必要なため以下を追記する。
.failureHandler(authenticationFailureHandler)
最後にlogin.htmlで内容を表示できるようにする。
<div th:if="${session[SPRING_SECURITY_LAST_EXCEPTION]}">
[[${session[SPRING_SECURITY_LAST_EXCEPTION]}]]
</div>
追記:Controllerでログイン成功時にもカウントをリセットしています。