您的位置:首页 > 其它

Shiro限制登录尝试次数

2017-06-30 00:24 274 查看
要限制用户登录尝试次数,必然要对用户名密码验证失败做记录,Shiro中用户名密码的验证交给了CredentialsMatcher 

所以在CredentialsMatcher里面检查,记录登录次数是最简单的做法。

我们用Ehcache来记录用户登录次数的计数,继承HashedCredentialsMatcher,加入缓存,在每次验证用户名密码之前先验证用户名尝试次数,如果超过5次就抛出尝试过多异常,否则验证用户名密码,验证成功把尝试次数清零,不成功则直接退出。

package org.jstudioframework.freeway.shiro.authc.credential;

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;

import java.util.concurrent.atomic.AtomicInteger;

/**
* 验证器,增加了登录次数校验功能
*/
public class RetryLimitCredentialsMatcher extends HashedCredentialsMatcher {
private static final Logger log = LoggerFactory.getLogger(RetryLimitCredentialsMatcher.class);

//集群中可能会导致出现验证多过5次的现象,因为AtomicInteger只能保证单节点并发
private Cache<String, AtomicInteger> lgoinRetryCache;

private int maxRetryCount = 5;

private String lgoinRetryCacheName;

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

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

@Override
public boolean doCredentialsMatch(AuthenticationToken token, AuthenticationInfo info) {
String username = (String) token.getPrincipal();
//retry count + 1
AtomicInteger retryCount = lgoinRetryCache.get(username);
if (null == retryCount) {
retryCount = new AtomicInteger(0);
lgoinRetryCache.put(username, retryCount);
}
if (retryCount.incrementAndGet() > 5) {
log.warn("username: " + username + " tried to login more than 5 times in period");
throw new ExcessiveAttemptsException("username: " + username + " tried to login more than 5 times in period"
);
}
boolean matches = super.doCredentialsMatch(token, info);
if (matches) {
//clear retry data
lgoinRetryCache.remove(username);
}
return matches;
}
}

UserRealm继承AuthorizingRealm,在其父类AuthenticatingRealm的getAuthenticationInfo方法中会调用credentialsMatcher的 doCredentialsMatch 来验证用户输入用户名密码是否匹配。

Ehcache配置

<!-- 登录记录缓存 锁定10分钟 -->
<cache name="lgoinRetryCache"
maxEntriesLocalHeap="2000"
eternal="false"
timeToIdleSeconds="600"
timeToLiveSeconds="0"
overflowToDisk="false"
statistics="true">
</cache>

Spring Shiro配置
<!-- Realm实现 -->
<bean id="userRealm" class="org.jstudioframework.freeway.shiro.UserRealm">
<!-- 将凭证匹配器设置到realm中,realm按照凭证匹配器的要求进行散列 -->
<property name="credentialsMatcher" ref="credentialsMatcher"/>
</bean>

<!-- 凭证匹配器 -->
<bean id="credentialsMatcher"
class="org.jstudioframework.freeway.shiro.authc.credential.RetryLimitCredentialsMatcher">
<constructor-arg index="0" ref="cacheManager"/>
<constructor-arg index="1" value="5"/>
<property name="hashAlgorithmName" value="md5"/>
<property name="hashIterations" value="1"/>
</bean>

<!-- 缓存管理器 -->
<bean id="cacheManager" class="org.apache.shiro.cache.ehcache.EhCacheManager">
<property name="cacheManagerConfigFile" value="classpath:cache/shiro-ehcache.xml"/>
</bean>
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签:  shiro