这次讲讲如何限制用户登录尝试次数,防止坏人多次尝试,恶意暴力破解密码的情况出现,要限制用户登录尝试次数,必然要对用户名密码验证失败做记录,Shiro中用户名密码的验证交给了CredentialsMatcher 所以在CredentialsMatcher里面检查,记录登录次数是最简单的做法。当登录失败次数达到限制,修改数据库中的状态字段,并返回前台错误信息。
因为之前的博客都是用的明文,这里就不对密码进行加密了,如果有需要加密,将自定义密码比较器从SimpleCredentialsMatcher改为HashedCredentialsMatcher 然后将对应的配置项打开就可以。
说在前面
非常抱歉,因为我之前整合的时候,只是注意功能,而没有注意细节,导致在登录失败之后,再次转发到 post方法/login 也就是真正的登录方法,导致 再次登录,然后导致下面密码错误3次之后 就 锁定 我设置的是5次.
所以将shiroConfig中的值改为shiroFilterFactoryBean.setLoginUrl("/");具体参考源代码。
另外 还需要将 自定义ShiroRealm 中 密码对比注销掉, 将密码对比 交给 底层的 密码比较器才可以 锁定用户,否则将 永远报密码错误。,具体代码 如下:
修改登录方法改为登录之后,重定向到/index
限制登录次数
自定义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-登录失败次数限制,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对亿速云网站的支持!
免责声明:本站发布的内容(图片、视频和文字)以原创、转载和分享为主,文章观点不代表本网站立场,如果涉及侵权请联系站长邮箱:is@yisu.com进行举报,并提供相关证据,一经查实,将立刻删除涉嫌侵权内容。