在上一次寫的文章中,爲你們說到了如何動態的從數據庫加載用戶、角色、權限信息,從而實現登陸驗證及受權。在實際的開發過程當中,咱們一般會有這樣的一個需求:當用戶屢次登陸失敗的時候,咱們應該將帳戶鎖定,等待必定的時間以後才能再次進行登陸操做。html
要實現屢次登陸失敗帳戶鎖定的功能,咱們須要先回顧一下基礎知識:前端
建議您先閱讀本文,若是您對本文的實現過程感到迷惑,建議您再翻看本號以前的相關內容。mysql
通常來講實現這個需求,咱們須要針對每個用戶記錄登陸失敗的次數nLock和鎖定帳戶的到期時間releaseTime。具體你是把這2個信息存儲在mysql、仍是文件中、仍是redis中等等,徹底取決於你對你所處的應用架構適用性的判斷。具體的實現邏輯無非就是:redis
這是一種很是典型的實現方式,筆者向你們介紹一款很是有用的開源軟件叫作:ratelimitj。這個軟件的功能主要是爲API訪問進行限流,也就是說能夠經過制定規則限制API接口的訪問頻率。那剛好登陸驗證接口也是API的一種啊,咱們正好也須要限制它在必定的時間內的訪問次數。spring
首先須要將ratelimitj經過maven座標引入到咱們的應用裏面來。咱們使用的是內存存儲的版本,還有redis存儲的版本,你們能夠根據本身的應用狀況選用。sql
<dependency> <groupid>es.moki.ratelimitj</groupid> <artifactid>ratelimitj-inmemory</artifactid> <version>0.4.1</version> </dependency>
以後經過繼承SimpleUrlAuthenticationFailureHandler ,實現onAuthenticationFailure方法。該實現是針對登陸失敗的結果的處理,在咱們以前的文章中已經講過。數據庫
@Component public class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { @Autowired UserDetailsManager userDetailsManager; //規則定義:1小時以內5次機會,就觸發限流行爲 Set<requestlimitrule> rules = Collections.singleton(RequestLimitRule.of(1 * 60, TimeUnit.MINUTES,5)); RequestRateLimiter limiter = new InMemorySlidingWindowRequestRateLimiter(rules); @Override public void onAuthenticationFailure(HttpServletRequest request, HttpServletResponse response, AuthenticationException exception) throws IOException, ServletException { String userId = //從request或request.getSession中獲取登陸用戶名 //計數器加1,並判斷該用戶是否已經到了觸發了鎖定規則 boolean reachLimit = limiter.overLimitWhenIncremented(userId); if(reachLimit){ //若是觸發了鎖定規則,經過UserDetails告知Spring Security鎖定帳戶 user.setAccountNonLocked(false); userDetailsManager.updateUser(user); SysUser user = (SysUser) userDetailsManager.loadUserByUsername(userId); } //此處省略經過response作json或html響應 } }
user.setAccountNonLocked(true);
重置鎖定狀態很簡單,就是上面的代碼。可是更重要的是如何選擇重置鎖定狀態的時機。筆者能想到幾種方案以下json