欢迎您访问程序员文章站本站旨在为大家提供分享程序员计算机编程知识!
您现在的位置是: 首页  >  IT编程

springboot整合shiro登录失败次数限制功能的实现代码

程序员文章站 2024-02-24 08:45:04
这次讲讲如何限制用户登录尝试次数,防止坏人多次尝试,恶意暴力破解密码的情况出现,要限制用户登录尝试次数,必然要对用户名密码验证失败做记录,shiro中用户名密码的验证交给了...

这次讲讲如何限制用户登录尝试次数,防止坏人多次尝试,恶意暴力破解密码的情况出现,要限制用户登录尝试次数,必然要对用户名密码验证失败做记录,shiro中用户名密码的验证交给了credentialsmatcher 所以在credentialsmatcher里面检查,记录登录次数是最简单的做法。当登录失败次数达到限制,修改数据库中的状态字段,并返回前台错误信息。
 因为之前的博客都是用的明文,这里就不对密码进行加密了,如果有需要加密,将自定义密码比较器从simplecredentialsmatcher改为hashedcredentialsmatcher 然后将对应的配置项打开就可以。

说在前面

非常抱歉,因为我之前整合的时候,只是注意功能,而没有注意细节,导致在登录失败之后,再次转发到 post方法/login 也就是真正的登录方法,导致 再次登录,然后导致下面密码错误3次之后 就 锁定 我设置的是5次.
所以将shiroconfig中的值改为shirofilterfactorybean.setloginurl("/");具体参考源代码。

 另外 还需要将 自定义shirorealm 中 密码对比注销掉, 将密码对比 交给 底层的 密码比较器才可以 锁定用户,否则将 永远报密码错误。,具体代码 如下:

springboot整合shiro登录失败次数限制功能的实现代码 

 修改登录方法改为登录之后,重定向到/index

springboot整合shiro登录失败次数限制功能的实现代码

限制登录次数

自定义retrylimithashedcredentialsmatcher继承simplecredentialsmatcher

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

/**
 * 配置密码比较器
 * @return
 */
@bean("credentialsmatcher")
public retrylimithashedcredentialsmatcher retrylimithashedcredentialsmatcher(){
 retrylimithashedcredentialsmatcher retrylimithashedcredentialsmatcher = new retrylimithashedcredentialsmatcher(ehcachemanager());

 //如果密码加密,可以打开下面配置
 //加密算法的名称
 //retrylimithashedcredentialsmatcher.sethashalgorithmname("md5");
 //配置加密的次数
 //retrylimithashedcredentialsmatcher.sethashiterations(1024);
 //是否存储为16进制
 //retrylimithashedcredentialsmatcher.setstoredcredentialshexencoded(true);

 return retrylimithashedcredentialsmatcher;
}

在shirorealm中配置密码比较器

/**
 * 身份认证realm; (这个需要自己写,账号密码校验;权限等)
 * @return
 */
@bean
public shirorealm shirorealm(){
 shirorealm shirorealm = new shirorealm();
 ......
 //配置自定义密码比较器
 shirorealm.setcredentialsmatcher(retrylimithashedcredentialsmatcher());
 return shirorealm;
}

在ehcache-shiro.xml添加缓存项

<!-- 登录失败次数缓存
  注意 timetoliveseconds 设置为300秒 也就是5分钟
  可以根据自己的需求更改
 -->
<cache name="passwordretrycache"
  maxentrieslocalheap="2000"
  eternal="false"
  timetoidleseconds="0"
  timetoliveseconds="300"
  overflowtodisk="false"
  statistics="true">
</cache>

在logincontroller中添加解除admin用户限制方法

/**
 * 解除admin 用户的限制登录 
 * 写死的 方便测试
 * @return
 */
@requestmapping("/unlockaccount")
public string unlockaccount(model model){
 model.addattribute("msg","用户解锁成功");

 retrylimithashedcredentialsmatcher.unlockaccount("admin");

 return "login";
}

注意:为了方便测试,记得将 unlockaccount 权限改为 任何人可访问。

在login.html页面 添加 解锁admin用户的按钮

<a href="/unlockaccount" rel="external nofollow" >解锁admin用户</a></button>

测试结果


springboot整合shiro登录失败次数限制功能的实现代码

总结

以上所述是小编给大家介绍的springboot整合shiro-登录失败次数限制,希望对大家有所帮助