- 資訊首頁(yè) > 開(kāi)發(fā)技術(shù) >
- SpringSecurity如何實(shí)現多次登錄失敗后賬戶(hù)鎖定功能
這篇文章將為大家詳細講解有關(guān)SpringSecurity如何實(shí)現多次登錄失敗后賬戶(hù)鎖定功能,小編覺(jué)得挺實(shí)用的,因此分享給大家做個(gè)參考,希望大家閱讀完這篇文章后可以有所收獲。
一、基礎知識回顧
要實(shí)現多次登錄失敗賬戶(hù)鎖定的功能,我們需要先回顧一下基礎知識:
Spring Security 不需要我們自己實(shí)現登錄驗證邏輯,而是將用戶(hù)、角色、權限信息以實(shí)現UserDetails和UserDetailsService接口的方式告知Spring Security。具體的登錄驗證邏輯Spring Security 會(huì )幫助我們實(shí)現。 UserDetails接口中有一個(gè)方法叫做isAccountNonLocked()用于判斷賬號是否被鎖定,也就是說(shuō)我們應該通過(guò)該方法對應的set方法setAccountNonLocked(false)告知Spring Security該登錄賬戶(hù)被鎖定。 那么應該在哪里判斷賬號登錄失敗的次數并執行鎖定機制呢?當然是我們之前文章給大家介紹的《自定義登錄成功及失敗結果處理》的AuthenticationFailureHandler。
建議您先閱讀本文,如果您對本文的實(shí)現過(guò)程感到迷惑,建議您再翻看本號之前的相關(guān)內容。
二、實(shí)現多次登錄失敗鎖定的原理
一般來(lái)說(shuō)實(shí)現這個(gè)需求,我們需要針對每一個(gè)用戶(hù)記錄登錄失敗的次數nLock和鎖定賬戶(hù)的到期時(shí)間releaseTime。具體你是把這2個(gè)信息存儲在、還是文件中、還是中等等,完全取決于你對你所處的應用架構適用性的判斷。具體的實(shí)現邏輯無(wú)非就是:
登陸失敗之后,從存儲中將nLock取出來(lái)加1。 如果nLock大于登陸失敗閾值(比如3次),則將nLock=0,然后設置releaseTime為當前時(shí)間加上鎖定周期。通過(guò)setAccountNonLocked(false)告知Spring Security該登錄賬戶(hù)被鎖定。 如果nLock小于等于1,則將nLock再次存起來(lái)。 在一個(gè)合適的時(shí)機,將鎖定狀態(tài)重置為setAccountNonLocked(true)。
這是一種非常典型的實(shí)現方式,筆者向大家介紹一款非常有用的開(kāi)源軟件叫做:ratelimitj。這個(gè)軟件的功能主要是為API訪(fǎng)問(wèn)進(jìn)行限流,也就是說(shuō)可以通過(guò)制定規則限制API接口的訪(fǎng)問(wèn)頻率。那恰好登錄驗證接口也是API的一種啊,我們正好也需要限制它在一定的時(shí)間內的訪(fǎng)問(wèn)次數。
三、具體實(shí)現
首先需要將ratelimitj通過(guò)maven坐標引入到我們的應用里面來(lái)。我們使用的是內存存儲的版本,還有redis存儲的版本,大家可以根據自己的應用情況選用。
<dependency> <groupId>es.moki.ratelimitj</groupId> <artifactId>ratelimitj-inmemory</artifactId> <version>0.4.1</version> </dependency>
之后通過(guò)繼承SimpleUrlAuthenticationFailureHandler ,實(shí)現onAuthenticationFailure方法。該實(shí)現是針對登錄失敗的結果的處理,在我們之前的文章中已經(jīng)講過(guò)。
@Componentpublic class MyAuthenticationFailureHandler extends SimpleUrlAuthenticationFailureHandler { @Autowired UserDetailsManager userDetailsManager; //規則定義:1小時(shí)之內5次機會(huì ),就觸發(fā)限流行為 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中獲取登錄用戶(hù)名 //計數器加1,并判斷該用戶(hù)是否已經(jīng)到了觸發(fā)了鎖定規則 boolean reachLimit = limiter.overLimitWhenIncremented(userId); if(reachLimit){ //如果觸發(fā)了鎖定規則,通過(guò)UserDetails告知Spring Security鎖定賬戶(hù) user.setAccountNonLocked(false); userDetailsManager.updateUser(user); SysUser user = (SysUser) userDetailsManager.loadUserByUsername(userId); } //此處省略通過(guò)response做json或html響應 }}
核心實(shí)現注意看代碼中的注釋
代碼中的SysUser為UserDetails的實(shí)現類(lèi),如果不知道如何實(shí)現請參考本號之前的文章
userDetailsManager被用于管理UserDetails信息,通過(guò)改變UserDetails改變Spring Security驗證行為。
四、重置鎖定狀態(tài)的時(shí)機
user.setAccountNonLocked(true);
重置鎖定狀態(tài)很簡(jiǎn)單,就是上面的代碼。但是更重要的是如何選擇重置鎖定狀態(tài)的時(shí)機。筆者能想到幾種方案如下
下一次登陸的時(shí)候,自定義過(guò)濾器,加在Spring Boot過(guò)濾器鏈最前端做鎖定狀態(tài)重置的判斷。 當登錄賬戶(hù)被鎖定之后,之后用戶(hù)的每一次登錄都會(huì )拋出LockedException。我們完全可以通過(guò)Spring Boot的全局異常捕獲機制,在其中捕獲LockedException,并做鎖定狀態(tài)的判斷及重置行為。 寫(xiě)一個(gè)Spring 的定時(shí)器輪詢(xún),當然這是最差的方案。
免責聲明:本站發(fā)布的內容(圖片、視頻和文字)以原創(chuàng )、來(lái)自互聯(lián)網(wǎng)轉載和分享為主,文章觀(guān)點(diǎn)不代表本網(wǎng)站立場(chǎng),如果涉及侵權請聯(lián)系QQ:712375056 進(jìn)行舉報,并提供相關(guān)證據,一經(jīng)查實(shí),將立刻刪除涉嫌侵權內容。
Copyright ? 2009-2021 56dr.com. All Rights Reserved. 特網(wǎng)科技 特網(wǎng)云 版權所有 珠海市特網(wǎng)科技有限公司 粵ICP備16109289號
域名注冊服務(wù)機構:阿里云計算有限公司(萬(wàn)網(wǎng)) 域名服務(wù)機構:煙臺帝思普網(wǎng)絡(luò )科技有限公司(DNSPod) CDN服務(wù):阿里云計算有限公司 中國互聯(lián)網(wǎng)舉報中心 增值電信業(yè)務(wù)經(jīng)營(yíng)許可證B2
建議您使用Chrome、Firefox、Edge、IE10及以上版本和360等主流瀏覽器瀏覽本網(wǎng)站