Shiro安全框架学习04 - 登录失败次数限制
为了防止被恶意暴力破解,我们都会进行登录失败超过一定次数进行锁定账号禁止登录。使用Ehcache提供缓存服务。
在前几篇代码的基础上添加ehcache依赖
<dependency><groupId>net.sf.ehcachegroupId><artifactId>ehcache-coreartifactId><version>2.6.6version>
dependency>
配置ehcache.xml
<ehcache name="es"><diskStore path="java.io.tmpdir"/><cache name="passwordRetryCache"maxEntriesLocalHeap="2000"eternal="false"timeToIdleSeconds="3600"timeToLiveSeconds="0"overflowToDisk="false"statistics="true">cache>ehcache>
编写自定义的CredentialsMatcher
import net.sf.ehcache.CacheManager;
import net.sf.ehcache.Ehcache;
import net.sf.ehcache.Element;
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 java.util.concurrent.atomic.AtomicInteger;public class RetryLimitHashedCredentialsMatcher extendsHashedCredentialsMatcher {private Ehcache passwordRetryCache;public RetryLimitHashedCredentialsMatcher() {CacheManager cacheManager = CacheManager.newInstance(CacheManager.class.getClassLoader().getResource("ehcache.xml"));passwordRetryCache = cacheManager.getCache("passwordRetryCache");}@Overridepublic boolean doCredentialsMatch(AuthenticationToken token,AuthenticationInfo info) {String username = (String)token.getPrincipal();//retry count + 1Element element = passwordRetryCache.get(username);if(element == null) {element = new Element(username , new AtomicInteger(0));passwordRetryCache.put(element);}AtomicInteger retryCount = (AtomicInteger)element.getObjectValue();if(retryCount.incrementAndGet() > 5) {//if retry count > 5 throwthrow new ExcessiveAttemptsException();}boolean matches = super.doCredentialsMatch(token, info);if(matches) {//clear retry countpasswordRetryCache.remove(username);}return matches;}
}
编写自定义的Realm
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.AuthenticationInfo;
import org.apache.shiro.authc.AuthenticationToken;
import org.apache.shiro.authc.LockedAccountException;
import org.apache.shiro.authc.SimpleAuthenticationInfo;
import org.apache.shiro.authc.UnknownAccountException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.PasswordService;
import org.apache.shiro.authz.AuthorizationInfo;
import org.apache.shiro.crypto.SecureRandomNumberGenerator;
import org.apache.shiro.crypto.hash.SimpleHash;
import org.apache.shiro.realm.AuthorizingRealm;
import org.apache.shiro.subject.PrincipalCollection;
import org.apache.shiro.util.ByteSource;public class UserRealm extends AuthorizingRealm {@Overrideprotected AuthorizationInfo doGetAuthorizationInfo(PrincipalCollection arg0) {// TODO Auto-generated method stubreturn null;}@Overrideprotected AuthenticationInfo doGetAuthenticationInfo(AuthenticationToken token) throws AuthenticationException {// TODO Auto-generated method stub//获取账号密码UsernamePasswordToken t = (UsernamePasswordToken) token;String password = new String(t.getPassword());String username = (String) token.getPrincipal();//获取数据库种的密码、盐(此处写死,测试用)User user = new User();user.setUsername(username);user.setPassword("b4b88b2ef28089f9c802df11bd216a33");user.setSalt("713183f112f48824613f0f05d0d10060");if (!"itmyhome".equals(username)) {// 抛出 帐号找不到异常throw new UnknownAccountException();}SimpleAuthenticationInfo authenticationInfo = new SimpleAuthenticationInfo(user.getUsername(), // 用户名user.getPassword(), // 密码ByteSource.Util.bytes(password + user.getSalt()),// salt=password+saltgetName() // realm name);return authenticationInfo;}}
测试类
import org.apache.shiro.SecurityUtils;
import org.apache.shiro.authc.AuthenticationException;
import org.apache.shiro.authc.ExcessiveAttemptsException;
import org.apache.shiro.authc.IncorrectCredentialsException;
import org.apache.shiro.authc.UsernamePasswordToken;
import org.apache.shiro.authc.credential.HashedCredentialsMatcher;
import org.apache.shiro.config.IniSecurityManagerFactory;
import org.apache.shiro.subject.Subject;
import org.apache.shiro.util.Factory;
import org.apache.shiro.mgt.SecurityManager;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;public class ShiroTest {private static Logger logger = LoggerFactory.getLogger(ShiroTest.class);public static void main(String[] args) {//获取SecurityManager工厂,此处使用Ini配置文件初始化SecurityManager Factory<SecurityManager> factory = new IniSecurityManagerFactory("classpath:auth.ini");//得到SecurityManager实例 并绑定给SecurityUtils SecurityManager securityManager = factory.getInstance();SecurityUtils.setSecurityManager(securityManager);//得到Subject及创建用户名/密码身份验证Token(即用户身份/凭证) Subject subject = SecurityUtils.getSubject();UsernamePasswordToken token = new UsernamePasswordToken("itmyhome","1234561");//模拟多次登录,密码错误超过5次即锁定账户for (int i = 1; i <= 6; i++){ try{//登录,即身份验证 subject.login(token);}catch(ExcessiveAttemptsException e){System.out.println("###### 账户已锁定 ########");}catch(IncorrectCredentialsException e){System.out.println("###### 密码错误 ########");}catch(AuthenticationException e){//身份验证失败System.out.println("###### 账号错误 ########");}}System.out.println("User is authenticated: " + subject.isAuthenticated());}
}
示例源码地址:xxx
本文来自互联网用户投稿,文章观点仅代表作者本人,不代表本站立场,不承担相关法律责任。如若转载,请注明出处。 如若内容造成侵权/违法违规/事实不符,请点击【内容举报】进行投诉反馈!
