Class LoginLockout
java.lang.Object
io.leandev.appfuse.security.lockout.LoginLockout
- All Implemented Interfaces:
org.springframework.beans.factory.Aware, org.springframework.context.ApplicationEventPublisherAware, org.springframework.security.core.userdetails.UserDetailsChecker
public class LoginLockout
extends Object
implements org.springframework.security.core.userdetails.UserDetailsChecker, org.springframework.context.ApplicationEventPublisherAware
登入失敗鎖定
完全走 Spring Security 既有機制,不包裝 AuthenticationProvider:
- 計數:監聽
AuthenticationFailureBadCredentialsEvent/AuthenticationSuccessEvent(框架的認證事件;與哪個 provider 認證無關) - 把關:實作
UserDetailsChecker,掛在DaoAuthenticationProvider的setPreAuthenticationChecks(...)——Spring 為帳號狀態檢查預留的插槽
接線(消費端組態):
var lockout = new LoginLockout(attemptCache, 5, Duration.ofMinutes(1));
AuthenticationManager manager = DaoAuthenticationManagers
.builder(userDetailsService, passwordEncoder, eventPublisher)
.preAuthenticationChecks(lockout) // 把關;builder 同時保證認證事件發布
.build();
鎖定時長:達閾值起以 step 遞增——閾值當次 = 1 × step,之後每多失敗一次多 1 × step。
需要別的曲線(固定時長、指數退避)覆寫 lockoutDuration(int),不需要另一個政策類。
鎖定中的帳號由本類拋 LockoutException(ApplicationException 家族,帶失敗次數與剩餘
分鐘),先於 Spring 的帳號狀態旗標檢查;未鎖定則委派 AccountStatusUserDetailsChecker
做標準旗標檢查(disabled/expired/locked)。
cache 停用或 isEnabled/get/put/remove 的 RuntimeException 只略過快取鎖定/計數; 密碼、帳號資格、政策與 SQL Session 仍由原認證鏈執行。Error 與初始化錯誤不降級。 Spring 管理的 bean(含 subclass)自動接入 AuditApplicationEvent 的 CACHE_UNAVAILABLE/ CACHE_RECOVERED;非 Spring 建立者可顯式設定 publisher。事件與 listener 普通例外不取代 登入結果,通知送達不保證;listener 應快速交給應用既有非同步通知能力。
-
Constructor Summary
ConstructorsConstructorDescriptionLoginLockout(Cache<String, AttemptRecord> cache, int threshold, Duration step) -
Method Summary
Modifier and TypeMethodDescriptionvoidcheck(org.springframework.security.core.userdetails.UserDetails user) 認證前檢查:鎖定中則拒絕,否則走標準帳號狀態檢查void解除鎖定並清除失敗記錄(供帳號管理面的「解鎖」操作)protected DurationlockoutDuration(int failureCount) 依失敗次數計算鎖定時長;覆寫此方法即可換成固定時長或指數退避voidonFailure(org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent event) 帳密錯誤:累計失敗,達閾值即設鎖定到期時間voidonSuccess(org.springframework.security.authentication.event.AuthenticationSuccessEvent event) 認證成功:清除記錄voidsetApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher publisher) Spring 建立本 bean 時自動接入既有 AuditApplicationEvent 通道。 非 Spring 消費端可顯式設定;listener 的普通例外不影響認證。
-
Constructor Details
-
LoginLockout
- Parameters:
cache- 失敗記錄快取(TTI 過期由快取本身承擔)threshold- 觸發鎖定的連續失敗次數step- 鎖定時長的遞增單位
-
-
Method Details
-
check
public void check(org.springframework.security.core.userdetails.UserDetails user) 認證前檢查:鎖定中則拒絕,否則走標準帳號狀態檢查- Specified by:
checkin interfaceorg.springframework.security.core.userdetails.UserDetailsChecker
-
onFailure
@EventListener public void onFailure(org.springframework.security.authentication.event.AuthenticationFailureBadCredentialsEvent event) 帳密錯誤:累計失敗,達閾值即設鎖定到期時間 -
onSuccess
@EventListener public void onSuccess(org.springframework.security.authentication.event.AuthenticationSuccessEvent event) 認證成功:清除記錄 -
clear
解除鎖定並清除失敗記錄(供帳號管理面的「解鎖」操作) -
lockoutDuration
依失敗次數計算鎖定時長;覆寫此方法即可換成固定時長或指數退避- Parameters:
failureCount- 連續失敗次數(≥ threshold)
-
setApplicationEventPublisher
public void setApplicationEventPublisher(org.springframework.context.ApplicationEventPublisher publisher) Spring 建立本 bean 時自動接入既有 AuditApplicationEvent 通道。 非 Spring 消費端可顯式設定;listener 的普通例外不影響認證。- Specified by:
setApplicationEventPublisherin interfaceorg.springframework.context.ApplicationEventPublisherAware
-