这次讲讲如何限制用户登录尝试次数,防止坏人多次尝试,恶意暴力破解密码的情况出现,要限制用户登录尝试次数,必然要对用户名密码验证失败做记录,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