shiro 实例 并发登录篇
来源:互联网 发布:手机版word软件 编辑:程序博客网 时间:2024/06/11 01:10
并发登录配置
<!-- 会话管理器 --> <bean id="sessionManager" class="org.apache.shiro.web.session.mgt.DefaultWebSessionManager"> <property name="globalSessionTimeout" value="1800000"/> <property name="deleteInvalidSessions" value="true"/> <property name="sessionValidationSchedulerEnabled" value="true" /> <property name="sessionValidationScheduler" ref="sessionValidationScheduler" /> <property name="sessionDAO" ref="sessionDAO" /> <property name="sessionIdCookieEnabled" value="true" /> <property name="sessionIdCookie" ref="sessionIdCookie" /> <property name="cacheManager" ref="cacheManager" /> </bean> <bean id="sessionDAO" class="org.apache.shiro.session.mgt.eis.EnterpriseCacheSessionDAO"> <property name="sessionIdGenerator" ref="sessionIdGenerator" /> <property name="activeSessionsCacheName" value="shiro-activeSessionCache" /> </bean> <bean id="sessionIdGenerator" class="org.apache.shiro.session.mgt.eis.JavaUuidSessionIdGenerator"/> <!-- 会话验证调度器 --> <bean id="sessionValidationScheduler" class="org.apache.shiro.session.mgt.ExecutorServiceSessionValidationScheduler"> <property name="interval" value="1800000" /> <property name="sessionManager" ref="sessionManager" /> </bean><!-- 安全管理器 --> <bean id="securityManager" class="org.apache.shiro.web.mgt.DefaultWebSecurityManager"> <property name="sessionManager" ref="sessionManager"/> .... </bean><!-- 自定义filter --> <bean id="KickoutSessionControlFilter" class="com.zm.web_shiro.web.filter.KickoutSessionControlFilter" > <property name="sessionManager" ref="sessionManager"/> <property name="cacheManager" ref="cacheManager"/> <property name="kickoutAfter" value="false"/> <property name="maxSession" value="1"/> <property name="kickoutUrl" value="/jsp/login.jsp?kickout=1"/> </bean> <bean id="shiroFilter" class="org.apache.shiro.spring.web.ShiroFilterFactoryBean"> <property name="securityManager" ref="securityManager"/> <property name="loginUrl" value="/jsp/login.jsp"/> <property name="unauthorizedUrl" value="/jsp/unauthorized.jsp"/> <property name="filterChainDefinitions"> <value> /index.jsp = anon /unauthorized.jsp = anon /jsp/login.jsp = anon /jsp/admin.jsp = authc,KickoutSessionControlFilter /jsp/user.jsp = user,KickoutSessionControlFilter /login/doLogout = logout /login/code = VcodeControlFilter /login/** = accessControlFilter /jsp/** = user,KickoutSessionControlFilter <!-- 资源 --> /css/** = anon /js/** = anon </value> </property> <property name="filters"> <map> <entry key="accessControlFilter" value-ref="accessControlFilter" /> <entry key="KickoutSessionControlFilter" value-ref="KickoutSessionControlFilter" /> <entry key="VcodeControlFilter" value-ref="VcodeControlFilter" /> </map> </property> </bean>
接下来就是把配置中的KickoutSessionControlFilter实现了
public class KickoutSessionControlFilter extends AccessControlFilter { private static final Logger log = LogManager.getLogger(KickoutSessionControlFilter.class); private String kickoutUrl; //踢出后到的地址 private boolean kickoutAfter = false; //踢出之前登录的/之后登录的用户 默认踢出之前登录的用户 private int maxSession = 1; //同一个帐号最大会话数 默认1 private SessionManager sessionManager; private Cache<String, Deque<Serializable>> cache; public void setKickoutUrl(String kickoutUrl) { this.kickoutUrl = kickoutUrl; } public void setKickoutAfter(boolean kickoutAfter) { this.kickoutAfter = kickoutAfter; } public void setMaxSession(int maxSession) { this.maxSession = maxSession; } public void setSessionManager(SessionManager sessionManager) { this.sessionManager = sessionManager; } public void setCacheManager(CacheManager cacheManager) { this.cache = cacheManager.getCache("shiro-kickout-session"); } @Override protected boolean isAccessAllowed(ServletRequest request, ServletResponse response, Object mappedValue) throws Exception { return false; } @Override 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(); log.info("username:" + username ); log.info("sessionId:" + sessionId ); //TODO 同步控制 Deque<Serializable> deque = cache.get(username); log.info("deque:" + deque); 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(); log.info("kickoutAfter:" + kickoutAfter + ",踢出后者"); } else { //否则踢出前者 kickoutSessionId = deque.removeLast(); log.info("kickoutAfter:" + kickoutAfter + ",踢出前者"); } try { Session kickoutSession = sessionManager.getSession(new DefaultSessionKey(kickoutSessionId)); if(kickoutSession != null) { //设置会话的kickout属性表示踢出了 kickoutSession.setAttribute("kickout", true); log.info("设置会话的kickout属性表示踢出了"); } } catch (Exception e) {//ignore exception } } //如果被踢出了,直接退出,重定向到踢出后的地址 if (session.getAttribute("kickout") != null) { log.info("会话被踢出了"); //会话被踢出了 try { subject.logout(); log.info("subject.logout(),登出并清理缓存"); } catch (Exception e) { //ignore } saveRequest(request); WebUtils.issueRedirect(request, response, kickoutUrl); return false; } return true; }}
运行效果如下(挤人需要用到两个浏览器):
阅读全文
0 0
- shiro 实例 并发登录篇
- shiro 并发登录人数控制
- shiro并发登录人数控制
- shiro 单点登录原理 实例
- 并发登录人数控制--Shiro系列(二)
- 并发登录人数控制--Shiro系列(二)
- 并发登录人数控制--Shiro系列(二)
- 并发登录人数控制——shiro
- Shiro登录验证实例详解与源码
- shiro框架之并发登录人数控制 十八
- Shiro安全框架入门篇(登录验证实例详解与源码)
- Shiro安全框架入门篇(登录验证实例详解与源码)
- Shiro安全框架入门篇(登录验证实例详解与源码)
- Shiro安全框架入门篇(登录验证实例详解与源码)
- Shiro安全框架入门篇(登录验证实例详解与源码)
- Shiro并发登录人数控制-后面登录的踢出前面登录的!
- Shiro 控制并发登录人数限制实现,登录踢出实现
- shiro源码分析篇3:用户登录缓存登录信息
- 转:sklearn中的模型评估
- kotlin实现的简单个人账户管理APP(三) 自定义View仿支付宝的密码输入框/密码相关逻辑
- iOS UITextView 随键盘弹出界面上移
- SpirngMVC框架下使用filter对字符进行过滤
- 正则表达式 替换两标签为空
- shiro 实例 并发登录篇
- 指针阅读技巧分析
- Nginx Location指令URI匹配规则详解
- Spring Boot集成mongoDB(十二)
- Objective-C(基础篇)九大基本类型
- 机器学习/深度学习/自然语言处理学习路线
- mxnet设置动态学习率(learning rate)
- 深入理解Java的接口和抽象类
- 小记1