shiro并发人数登录控制的实现代码

所属分类: 软件编程 / java 阅读数: 20
收藏 0 赞 0 分享

在某些项目中可能会遇到如每个账户同时只能有一个人登录或几个人同时登录,如果同时有多人登录:要么不让后者登录;要么踢出前者登录(强制退出)。比如spring security就直接提供了相应的功能;Shiro的话没有提供默认实现,不过可以很容易的在Shiro中加入这个功能。 

通过Shiro Filter机制扩展KickoutSessionControlFilter完成。 

首先来看看如何配置使用(spring-config-shiro.xml)  

kickoutSessionControlFilter用于控制并发登录人数的 

Java代码  

<bean id="kickoutSessionControlFilter" 
class="com.github.zhangkaitao.shiro.chapter18.web.shiro.filter.KickoutSessionControlFilter"> 
 <property name="cacheManager" ref="cacheManager"/> 
 <property name="sessionManager" ref="sessionManager"/> 
 <property name="kickoutAfter" value="false"/> 
 <property name="maxSession" value="2"/> 
 <property name="kickoutUrl" value="/login?kickout=1"/> 
</bean> 

cacheManager:使用cacheManager获取相应的cache来缓存用户登录的会话;用于保存用户—会话之间的关系的;

sessionManager:用于根据会话ID,获取会话进行踢出操作的;

kickoutAfter:是否踢出后来登录的,默认是false;即后者登录的用户踢出前者登录的用户;

maxSession:同一个用户最大的会话数,默认1;比如2的意思是同一个用户允许最多同时两个人登录;

kickoutUrl:被踢出后重定向到的地址; 

shiroFilter配置 

Java代码  

<bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> 
 <property name="securityManager" ref="securityManager"/> 
 <property name="loginUrl" value="/login"/> 
 <property name="filters"> 
  <util:map> 
  <entry key="authc" value-ref="formAuthenticationFilter"/> 
  <entry key="sysUser" value-ref="sysUserFilter"/> 
  <entry key="kickout" value-ref="kickoutSessionControlFilter"/> 
  </util:map> 
 </property> 
 <property name="filterChainDefinitions"> 
  <value> 
  /login = authc 
  /logout = logout 
  /authenticated = authc 
  /** = kickout,user,sysUser 
  </value> 
 </property> 
 </bean> 

此处配置除了登录等之外的地址都走kickout拦截器进行并发登录控制。 

测试

此处因为maxSession=2,所以需要打开3个浏览器(需要不同的浏览器,如IE、Chrome、Firefox),分别访问http://localhost:8080/chapter18/进行登录;然后刷新第一次打开的浏览器,将会被强制退出,如显示下图: 

KickoutSessionControlFilter核心代码: 

Java代码  

protected boolean onAccessDenied(ServletRequest request, ServletResponse response) throws Exception { 
 Subject subject = getSubject(request, response); 
 if(!subject.isAuthenticated() && !subject.isRemembered()) { 
 //如果没有登录,直接进行之后的流程 
 return true; 
 } 
 Session session = subject.getSession(); 
 String username = (String) subject.getPrincipal(); 
 Serializable sessionId = session.getId(); 
 //TODO 同步控制 
 Deque<Serializable> deque = cache.get(username); 
 if(deque == null) { 
 deque = new LinkedList<Serializable>(); 
 cache.put(username, deque); 
 } 
 //如果队列里没有此sessionId,且用户没有被踢出;放入队列 
 if(!deque.contains(sessionId) && session.getAttribute("kickout") == null) { 
 deque.push(sessionId); 
 } 
 //如果队列里的sessionId数超出最大会话数,开始踢人 
 while(deque.size() > maxSession) { 
 Serializable kickoutSessionId = null; 
 if(kickoutAfter) { //如果踢出后者 
  kickoutSessionId = deque.removeFirst(); 
 } else { //否则踢出前者 
  kickoutSessionId = deque.removeLast(); 
 } 
 try { 
  Session kickoutSession = 
  sessionManager.getSession(new DefaultSessionKey(kickoutSessionId)); 
  if(kickoutSession != null) { 
  //设置会话的kickout属性表示踢出了 
  kickoutSession.setAttribute("kickout", true); 
  } 
 } catch (Exception e) {//ignore exception 
 } 
 } 
 //如果被踢出了,直接退出,重定向到踢出后的地址 
 if (session.getAttribute("kickout") != null) { 
 //会话被踢出了 
 try { 
  subject.logout(); 
 } catch (Exception e) { //ignore 
 } 
 saveRequest(request); 
 WebUtils.issueRedirect(request, response, kickoutUrl); 
 return false; 
 } 
 return true; 
} 

此处使用了Cache缓存用户名—会话id之间的关系;如果量比较大可以考虑如持久化到数据库/其他带持久化的Cache中;另外此处没有并发控制的同步实现,可以考虑根据用户名获取锁来控制,减少锁的粒度。

以上所述是小编给大家介绍的shiro并发人数登录控制的实现代码,希望对大家有所帮助,如果大家有任何疑问请给我留言,小编会及时回复大家的。在此也非常感谢大家对脚本之家网站的支持!

更多精彩内容其他人还在看

Java的面向对象编程基本概念学习笔记整理

这篇文章主要介绍了Java的面向对象编程基本概念学习笔记整理,包括类与方法以及多态等支持面向对象语言中的重要特点,需要的朋友可以参考下
收藏 0 赞 0 分享

Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法

这篇文章主要介绍了Eclipse下编写java程序突然不会自动生成R.java文件和包的解决办法 的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

基于Java实现杨辉三角 LeetCode Pascal's Triangle

这篇文章主要介绍了基于Java实现杨辉三角 LeetCode Pascal's Triangle的相关资料,需要的朋友可以参考下
收藏 0 赞 0 分享

Java中Spring获取bean方法小结

Spring是一个轻量级的控制反转(IoC)和面向切面(AOP)的容器框架,如何在程序中获取Spring配置的bean呢?下面通过本文给大家介绍Java中Spring获取bean方法小结,对spring获取bean方法相关知识感兴趣的朋友一起学习吧
收藏 0 赞 0 分享

如何计算Java对象占用了多少空间?

在Java中没有sizeof运算符,所以没办法知道一个对象到底占用了多大的空间,但是在分配对象的时候会有一些基本的规则,我们根据这些规则大致能判断出来对象大小,需要的朋友可以参考下
收藏 0 赞 0 分享

剖析Java中的事件处理与异常处理机制

这篇文章主要介绍了Java中的事件处理与异常处理机制,讲解Java是如何对事件或者异常作出响应以及定义异常的一些方法,需要的朋友可以参考下
收藏 0 赞 0 分享

详解Java的Struts2框架的结构及其数据转移方式

这篇文章主要介绍了详解Java的Struts2框架的结构及其数据转移方式,Struts框架是Java的SSH三大web开发框架之一,需要的朋友可以参考下
收藏 0 赞 0 分享

Java封装好的mail包发送电子邮件的类

本文给大家分享了2个java封装好的mail包发送电子邮件的类,并附上使用方法,小伙伴们可以根据自己的需求自由选择。
收藏 0 赞 0 分享

在Java的Struts中判断是否调用AJAX及用拦截器对其优化

这篇文章主要介绍了在Java的Struts中判断是否调用AJAX及用拦截器对其优化的方法,Struts框架是Java的SSH三大web开发框架之一,需要的朋友可以参考下
收藏 0 赞 0 分享

java多线程Future和Callable类示例分享

JAVA多线程实现方式主要有三种:继承Thread类、实现Runnable接口、使用ExecutorService、Callable、Future实现有返回结果的多线程。其中前两种方式线程执行完后都没有返回值,只有最后一种是带返回值的。今天我们就来研究下Future和Callab
收藏 0 赞 0 分享
查看更多