這次講講如何限制用戶登錄嘗試次數,防止壞人多次嘗試,惡意暴力破解密碼的情況出現,要限制用戶登錄嘗試次數,必然要對用戶名密碼驗證失敗做記錄,shiro中用戶名密碼的驗證交給了credentialsmatcher 所以在credentialsmatcher里面檢查,記錄登錄次數是最簡單的做法。當登錄失敗次數達到限制,修改數據庫中的狀態字段,并返回前臺錯誤信息。
因為之前的博客都是用的明文,這里就不對密碼進行加密了,如果有需要加密,將自定義密碼比較器從simplecredentialsmatcher改為hashedcredentialsmatcher 然后將對應的配置項打開就可以。
說在前面
非常抱歉,因為我之前整合的時候,只是注意功能,而沒有注意細節,導致在登錄失敗之后,再次轉發到 post方法/login 也就是真正的登錄方法,導致 再次登錄,然后導致下面密碼錯誤3次之后 就 鎖定 我設置的是5次.
所以將shiroconfig中的值改為shirofilterfactorybean.setloginurl("/");具體參考源代碼。
另外 還需要將 自定義shirorealm 中 密碼對比注銷掉, 將密碼對比 交給 底層的 密碼比較器才可以 鎖定用戶,否則將 永遠報密碼錯誤。,具體代碼 如下:
修改登錄方法改為登錄之后,重定向到/index
限制登錄次數
自定義retrylimithashedcredentialsmatcher繼承simplecredentialsmatcher
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
|
package com.springboot.test.shiro.config.shiro; import java.util.concurrent.atomic.atomicinteger; import com.springboot.test.shiro.modules.user.dao.usermapper; import com.springboot.test.shiro.modules.user.dao.entity.user; import org.apache.log4j.logger; import org.apache.shiro.authc.authenticationinfo; import org.apache.shiro.authc.authenticationtoken; import org.apache.shiro.authc.lockedaccountexception; import org.apache.shiro.authc.credential.simplecredentialsmatcher; import org.apache.shiro.cache.cache; import org.apache.shiro.cache.cachemanager; import org.springframework.beans.factory.annotation.autowired; /** * @author: wangsaichao * @date: 2018/5/25 * @description: 登陸次數限制 */ public class retrylimithashedcredentialsmatcher extends simplecredentialsmatcher { private static final logger logger = logger.getlogger(retrylimithashedcredentialsmatcher. class ); @autowired private usermapper usermapper; private cache<string, atomicinteger> passwordretrycache; public retrylimithashedcredentialsmatcher(cachemanager cachemanager) { passwordretrycache = cachemanager.getcache( "passwordretrycache" ); } @override public boolean docredentialsmatch(authenticationtoken token, authenticationinfo info) { //獲取用戶名 string username = (string)token.getprincipal(); //獲取用戶登錄次數 atomicinteger retrycount = passwordretrycache.get(username); if (retrycount == null ) { //如果用戶沒有登陸過,登陸次數加1 并放入緩存 retrycount = new atomicinteger( 0 ); passwordretrycache.put(username, retrycount); } if (retrycount.incrementandget() > 5 ) { //如果用戶登陸失敗次數大于5次 拋出鎖定用戶異常 并修改數據庫字段 user user = usermapper.findbyusername(username); if (user != null && "0" .equals(user.getstate())){ //數據庫字段 默認為 0 就是正常狀態 所以 要改為1 //修改數據庫的狀態字段為鎖定 user.setstate( "1" ); usermapper.update(user); } logger.info( "鎖定用戶" + user.getusername()); //拋出用戶鎖定異常 throw new lockedaccountexception(); } //判斷用戶賬號和密碼是否正確 boolean matches = super .docredentialsmatch(token, info); if (matches) { //如果正確,從緩存中將用戶登錄計數 清除 passwordretrycache.remove(username); } return matches; } /** * 根據用戶名 解鎖用戶 * @param username * @return */ public void unlockaccount(string username){ user user = usermapper.findbyusername(username); if (user != null ){ //修改數據庫的狀態字段為鎖定 user.setstate( "0" ); usermapper.update(user); passwordretrycache.remove(username); } } } |
在shiroconfig中配置該bean
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
|
/** * 配置密碼比較器 * @return */ @bean ( "credentialsmatcher" ) public retrylimithashedcredentialsmatcher retrylimithashedcredentialsmatcher(){ retrylimithashedcredentialsmatcher retrylimithashedcredentialsmatcher = new retrylimithashedcredentialsmatcher(ehcachemanager()); //如果密碼加密,可以打開下面配置 //加密算法的名稱 //retrylimithashedcredentialsmatcher.sethashalgorithmname("md5"); //配置加密的次數 //retrylimithashedcredentialsmatcher.sethashiterations(1024); //是否存儲為16進制 //retrylimithashedcredentialsmatcher.setstoredcredentialshexencoded(true); return retrylimithashedcredentialsmatcher; } |
在shirorealm中配置密碼比較器
1
2
3
4
5
6
7
8
9
10
11
12
|
/** * 身份認證realm; (這個需要自己寫,賬號密碼校驗;權限等) * @return */ @bean public shirorealm shirorealm(){ shirorealm shirorealm = new shirorealm(); ...... //配置自定義密碼比較器 shirorealm.setcredentialsmatcher(retrylimithashedcredentialsmatcher()); return shirorealm; } |
在ehcache-shiro.xml添加緩存項
1
2
3
4
5
6
7
8
9
10
11
12
|
<!-- 登錄失敗次數緩存 注意 timetoliveseconds 設置為 300 秒 也就是 5 分鐘 可以根據自己的需求更改 --> <cache name= "passwordretrycache" maxentrieslocalheap= "2000" eternal= "false" timetoidleseconds= "0" timetoliveseconds= "300" overflowtodisk= "false" statistics= "true" > </cache> |
在logincontroller中添加解除admin用戶限制方法
1
2
3
4
5
6
7
8
9
10
11
12
13
|
/** * 解除admin 用戶的限制登錄 * 寫死的 方便測試 * @return */ @requestmapping ( "/unlockaccount" ) public string unlockaccount(model model){ model.addattribute( "msg" , "用戶解鎖成功" ); retrylimithashedcredentialsmatcher.unlockaccount( "admin" ); return "login" ; } |
注意:為了方便測試,記得將 unlockaccount 權限改為 任何人可訪問。
在login.html頁面 添加 解鎖admin用戶的按鈕
1
|
<a href= "/unlockaccount" rel= "external nofollow" >解鎖admin用戶</a></button> |
測試結果
總結
以上所述是小編給大家介紹的springboot整合shiro-登錄失敗次數限制,希望對大家有所幫助,如果大家有任何疑問請給我留言,小編會及時回復大家的。在此也非常感謝大家對服務器之家網站的支持!
原文鏈接:https://blog.csdn.net/qq_34021712/article/details/80461177