Spring 自带内存缓存配置,校验密码输入次数锁定账户5分钟及过期时间设置(二)

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_18808965/article/details/82557695

 1、经过参考一些文档整合了,校验密码输入错误次数及锁定多久的时间设置。希望能帮助有需要的朋友。好用请拿走,给个好评谢谢!

package com.etop.shiro;

import java.sql.Date;
import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Map;
import java.util.Set;
import java.util.Timer;
import java.util.TimerTask;
import java.util.concurrent.atomic.AtomicInteger;

import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.cache.Cache;
import org.apache.shiro.cache.CacheManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

/**
 * 验证器,增加了登录次数校验及过期时间设置功能
 * @author WangBenYan
 */
@SuppressWarnings("unused")
public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher {

	private static final Logger log = LoggerFactory.getLogger(RetryLimitCredentialsMatcher.class);

	// 集群中可能会导致出现验证多过5次的现象,因为AtomicInteger只能保证单节点并发
	private Cache<String, AtomicInteger> lgoinRetryCache;
	// 缓存用户的错误次数及过期时间
	private Cache<String, CacheData> loginCache;

	private int maxRetryCount = 2;

	private String lgoinRetryCacheName;

	private CacheData errorCount;
	
	private static SimpleDateFormat sf = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss");
	//当前缓存时间
	private static String currentdate ;
	
	// 过期时间(单位,毫秒)
	private long expireTime = 300000L;

	public void setMaxRetryCount(int maxRetryCount) {
		this.maxRetryCount = maxRetryCount;
	}

	public RetryLimitCredentialsMatcher(CacheManager cacheManager, String lgoinRetryCacheName) {
		this.lgoinRetryCacheName = lgoinRetryCacheName;
		loginCache = cacheManager.getCache(lgoinRetryCacheName);
	}

	@Override
	public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
		String username = (String) token.getPrincipal();
		// errorCount count + 1
		errorCount = loginCache.get(username);
		AtomicInteger tempCount = null;
		if (null == errorCount) {
			tempCount = new AtomicInteger(0);
			// 记录缓存次数及过期时间
			errorCount = new CacheData(tempCount, expireTime);
			loginCache.put(username, errorCount);
			currentdate = sf.format(new Date(Calendar.getInstance().getTimeInMillis()));
		}
		if (errorCount.data.incrementAndGet() >= maxRetryCount) {
			log.info("username: " + username + " 因用户连续输错密码次数超过{}次被锁定,请5分钟后再登录,当前登录次数:{}", maxRetryCount,errorCount.data);
			/* 启动定时任务清理过期缓存,避免内存溢出 */
			Timer t = new Timer();
			/* 一分钟调度一次 */
			log.info(" **************** 开启定时清理过期的缓存任务  ,当前任务名称:{} **************** ", username);
			t.schedule(new ClearTimerTask(loginCache), 0, 60 * 1000);
			throw new ExcessiveAttemptsException("username: " + username + " tried to login more than 5 times in period");
		}
		boolean matches = super.doCredentialsMatch(token, info);
		if (matches) {
			// clear cache data
			loginCache.remove(username);
		}
		return matches;
	}
	/**
	 * 清理过期数据定时任务
	 * @author WangBenYan
	 */
	private static class ClearTimerTask extends TimerTask {

		Cache<String, CacheData> cache;

		public ClearTimerTask(Cache<String, CacheData> cache) {
			this.cache = cache;
		}

		@Override
		public void run() {
			Set<String> keys = cache.keys();
			log.info("ClearTimerTask run......{}", keys.toString());
			CacheData data;
			for (String key : keys) {
				data = cache.get(key);
				String overTime = sf.format(new Date(data.expireTime));
				if (data.expireTime <= 0) {
					log.info(" **************** 缓存永不过期,缓存数据:" + key + " ,错误次数:" + data.data + " ,过期时间:" + overTime+ " ,缓存时间: " + currentdate);
					continue;
				}
				/* 到期时间 > 当前时间,则继续 */
				if (data.expireTime > Calendar.getInstance().getTimeInMillis()) {
					log.info(" **************** 缓存的用户 :" + key + " ,错误次数:" + data.data + " ,过期时间:" + overTime+ " ,缓存时间: " + currentdate);
					continue;
				}
				log.info(" **************** 开始清除缓存 **************** : " + key);
				cache.remove(key);
				log.info(" **************** 定时清理过期的缓存... {} ", cache.get(key));
				this.cancel();
			}
		}

	}

	private static class CacheData {
		// 缓存数据
		private AtomicInteger data;
		// 过期时间(单位,毫秒)
		private long expireTime;

		public CacheData(AtomicInteger errorcount, long expire) {
			log.info(" **************** 缓存认证错误次数:" + errorcount + " 过期时间毫秒数:" + expire);
			this.data = errorcount;
			if (expire <= 0) {
				this.expireTime = 0L;
			} else {
				this.expireTime = Calendar.getInstance().getTimeInMillis() + expire;
			}
		}
	}
}

猜你喜欢

转载自blog.csdn.net/qq_18808965/article/details/82557695
今日推荐