為防止暴力破解用戶賬號的行為,在輸入賬號和密碼時一般都會限制用戶嘗試密碼輸出錯誤的次數,如果用戶多次輸錯密碼后,將在一段時間內鎖定賬號,常見的有銀行類APP、個稅App等應用,如下是用戶賬號密碼輸入錯誤的提示圖:
如何實現10秒內連續登錄失敗超過3次的用戶呢有以下幾種實現方案
1、登錄日志表實現方案
每次用戶登錄的時候,無論登錄是否成功與否,我們后端都要記錄用戶的登錄信息到數據表中,如下一張簡單的登錄日志表:
日志表中記錄用戶賬號、登錄的來源、登錄的ip、本次登錄是否成功以及登錄時間等基本信息。通過日志表我們就可以實現統計10秒內連續登錄失敗超過3次的用戶,如下的流程圖
用戶登錄的時候,后端需要查詢日志表做統計,通過借助Mysql的一個強大的sql窗口函數row_number()來統計連續的10秒內是否存在超過3次的登錄失敗的情況:
(1)如果存在連續10秒超過3次登錄失敗,就需要鎖定用戶的賬號并發送一個郵件通知用戶。(2)如果不存在連續10秒超過3次登錄失敗的情況,返回用戶的登錄情況(賬號密碼輸入正確,返回登錄成功的響應,賬號密碼輸入錯誤,就返回登錄失敗的提示)。使用日志表實現統計連續10秒超過3次登錄失敗的用戶方案中存在如下的問題:(a)統計在10秒之內用戶超過3次登錄失敗的用戶登錄數據,需要使用row_number()窗口函數,一方面統計的sql語句比較復雜,另一方面sql執行的效率也不高。(b)記錄用戶的登錄日志,隨著時間的推移數據量會越來越大,這樣會影響性能,后續需要做冷數據的遷移,將指定時間(如1個月前)的用戶登錄數據遷移到冷表中。
2、Redis實現方案
借助Redis實現統計在10秒之內用戶超過3次登錄失敗的流程圖如下所示:
Redis中以用戶id為key(如123_login_record),連續登錄失敗次數為value,并且設置key的過期時間為10秒。
用戶請求登錄時候,服務端檢測當前用戶輸入的賬號密碼是否正確:(a)如果用戶賬號密碼驗證通過(登錄成功),此時需要將這個用戶Redis中的key刪除,目的是用來實現記錄連續失敗的功能。(2)如果用戶登錄失敗,那么需要使用setnx命令來設置用戶登錄失敗的信息,并且Redis的key過期時間為10秒,這個過程中如果set失敗代表用戶之前已經登錄失敗過,直接把次數加1就可以了。最后我們只需拿到這個用戶賬號對應的value,判斷這個value是否大于等于3,如果大于等3次,那么需要發送登錄異常的提示郵件,鎖定用戶賬號一段時間。
總結:
(1)完成統計10秒內連續登錄失敗超過3次的用戶,可以借助登錄日志表實現,也可以借助Redis實現方案。(2)登錄日志表實現方案中是借助sql窗口函數row_number()來統計,這種實現方式不但統計的sql復雜,而且隨著登錄日志表中數據量的增加,sql的執行效率也很低。(3)Redis實現方案key加過期時間來實現,如果用戶登錄成功就刪除這個key,登錄失敗就在原先登錄失敗的基礎上加1。但為了保證Redis中多個指令執行過程中的原子性,可以借助lua腳本來保證原子性。