IT世界|java:shiro高级篇——4( 二 )


自定义过滤器:继承AccessControlFilter使用redis队列控制账号在线数目实现步骤:
1、只针对登录用户处理 , 首先判断是否登录2、使用RedissionClien创建队列3、判断当前sessionId是否存在于此用户的队列=key:登录名value:多个sessionId4、不存在则放入队列尾端==>存入sessionId5、判断当前队列大小是否超过限定此账号的可在线人数6、超过:*从队列头部拿到用户sessionId*从sessionManger根据sessionId拿到session*从sessionDao中移除session会话7、未超过:放过操作2、代码实现【1】KickedOutAuthorizationFilterpackagecom.itheima.shiro.filter;importcom.itheima.shiro.core.impl.RedisSessionDao;importcom.itheima.shiro.utils.EmptyUtil;importcom.itheima.shiro.utils.ShiroUserUtil;importlombok.extern.log4j.Log4j2;importorg.apache.shiro.session.ExpiredSessionException;importorg.apache.shiro.session.Session;importorg.apache.shiro.session.UnknownSessionException;importorg.apache.shiro.session.mgt.DefaultSessionKey;importorg.apache.shiro.session.mgt.eis.SessionDAO;importorg.apache.shiro.subject.Subject;importorg.apache.shiro.web.filter.AccessControlFilter;importorg.apache.shiro.web.session.mgt.DefaultWebSessionManager;importorg.redisson.api.RDeque;importorg.redisson.api.RedissonClient;importorg.springframework.beans.factory.annotation.Autowired;importorg.springframework.stereotype.Component;importjavax.annotation.Resource;importjavax.servlet.ServletRequest;importjavax.servlet.ServletResponse;/***@Description:*/@Log4j2publicclassKickedOutAuthorizationFilterextendsAccessControlFilter{privateRedissonClientredissonClient;privateSessionDAOredisSessionDao;privateDefaultWebSessionManagersessionManager;publicKickedOutAuthorizationFilter(RedissonClientredissonClient,SessionDAOredisSessionDao,DefaultWebSessionManagersessionManager){this.redissonClient=redissonClient;this.redisSessionDao=redisSessionDao;this.sessionManager=sessionManager;}@OverrideprotectedbooleanisAccessAllowed(ServletRequestservletRequest,ServletResponseservletResponse,Objecto)throwsException{returnfalse;}@OverrideprotectedbooleanonAccessDenied(ServletRequestservletRequest,ServletResponseservletResponse)throwsException{Subjectsubject=getSubject(servletRequest,servletResponse);if(!subject.isAuthenticated()){//如果没有登录 , 直接进行之后的流程returntrue;}//存放session对象进入队列StringsessionId=ShiroUserUtil.getShiroSessionId();StringLoginName=ShiroUserUtil.getShiroUser().getLoginName();RDequequeue=redissonClient.getDeque("KickedOutAuthorizationFilter:"+LoginName);//判断sessionId是否存在于此用户的队列中booleanflag=queue.contains(sessionId);if(!flag){queue.addLast(sessionId);}//如果此时队列大于1 , 则开始踢人if(queue.size()>1){sessionId=queue.getFirst();queue.removeFirst();Sessionsession=null;try{session=sessionManager.getSession(newDefaultSessionKey(sessionId));}catch(UnknownSessionExceptionex){log.info("session已经失效");}catch(ExpiredSessionExceptionexpiredSessionException){log.info("session已经过期");}if(!EmptyUtil.isNullOrEmpty(session)){redisSessionDao.delete(session);}}returntrue;}}【2】修改ShiroConfig/***@Description自定义过滤器定义*/privateMapfilters(){Mapmap=newHashMap();map.put("roleOr",newRolesOrAuthorizationFilter());map.put("kickedOut",newKickedOutAuthorizationFilter(redissonClient(),redisSessionDao(),shiroSessionManager()));returnmap;}【3】修改authentication.properties#静态资源不过滤/static/**=anon#登录链接不过滤/login/**=anon#访问/resource/**需要有admin的角色/resource/**=role-or[MangerRole,SuperAdmin]#其他链接是需要登录的/**=kickedOut,auth3、测试使用谷歌访问 , 使用admin/pass登陆