JavaWeb-实现多ip、异地 同时登录踢人下线
- 所用知识点罗列:
cookie 、session、serverlet过滤器、serverlet监听器,前提环境是基于Session实现的登录功能
(Session中存放了登录者的ip,userName等信息作已登录标记)
- 需要理解的基本概念
Session是基于cookie的,请求会话中,通过浏览器cookie携带的JsessionId
的sessionId号来找到服务器中相应的Session的.
如果没有设置cookie的有效时间,一旦浏览器关闭,cookie就消失了,
其携带的sessionId也就丢失了,
这时即使服务器中的当前用户的Session还未过期失效,依然存在,也无法找到了,基本等于是销毁了.
- 问题关键所在
正常使用Session实现的登录时把登陆标记存放在Session中,在一次会话中有效。
Session是以会话为隔离的,(其他浏览器或其他电脑也可以在打开一个会话),不同会话就可以创建同一用户的不同session。
也就造成了服务器端可以有任意多个SessionId不同,但Session内容却相同的Session,
也即是同一个用户可以在多个浏览器登录,无论是否是在同一台电脑(ip)、同一个地区。
这也是我们要实现多ip登录踢人下线功能要解决的问题。
- 解决方案思路
1. 自己实现MySessionContext类搞一个map静态成员变量以<SessionId,Session>的方式装所有的Session,放服务器的运行内存中待用.
(其实使用serverletContext作为容器也可以替代Session和这个自己实现的SessionContext)2. 搞一个Session监听器,监听Session的创建和销毁,在新的session创建时将其加入到上面自己创建的
MySessionContext的静态成员变量map中,Session销毁时(或者用户注销登录时)把他的Session移除出map,
并用Session.invalidate()销毁.3. 用一个过滤器拦截过滤登录请求,获取登录用户的登录标记,然后遍历装有Session的map,
对照是否有当前登录用户的Session存在,如果没有就放行通过;
如果有,取出找到的session(也即是前一个登录者生成的Session)移除出MySessionContext的map容器,
并销毁这个Session(调用invalid()方法).此时前一个登录者再刷新页面时发现Session已经不存在了,配合先前做的Session过期过滤处理,就会和Session过期有一样的效果——下线.
- 参考代码
登录操作:
//获取登录ip地址
String ip = request.getRemoteAddr();
//将登录者的ip放入到session中
request.getSession().setAttribute(ESessionKey.LoginIP.key, ip);
request.getSession().setAttribute(ESessionKey.UserId.key, user.getUserId());// 将用户id存放到session中,作为已登录标记
MySessionContext实现
public class MySessionContext {private static HashMap<String,HttpSession> mymap = new HashMap<String,HttpSession>();public static synchronized void AddSession(HttpSession session) {if (session != null) {mymap.put(session.getId(), session);}}public static synchronized void DelSession(HttpSession session) {if (session != null) {HttpSession session2 = mymap.remove(session.getId());//移出sessionif(session2!=null){session2.invalidate();//将从sessionContext中移出的Session失效 --相当于清除当前Session对应的登录用户}}}public static synchronized HttpSession getSession(String session_id) {if (session_id == null)return null;return (HttpSession)mymap.get(session_id);}public static HashMap<String, HttpSession> getMymap() {return mymap;}
}
Session监听器
public class SessionCounter implements HttpSessionListener { private static int activeSessions = 0; public void sessionCreated(HttpSessionEvent se) { MySessionContext.AddSession(se.getSession());activeSessions++; System.out.println("++++++++玩家上线了++++++++");} public void sessionDestroyed(HttpSessionEvent se) { if(activeSessions > 0) activeSessions--;HttpSession session = se.getSession();MySessionContext.DelSession(session);} public static int getActiveSessions() { return activeSessions; }
}
踢人下线过滤器核心代码
public void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {HttpServletRequest request = (HttpServletRequest)req;HttpServletResponse response = (HttpServletResponse)resp;String localIp = request.getRemoteAddr();//获取本地ipHttpSession session = null;String user_id = (String)request.getParameter("userId"); //登录请求时填写的 if(StringUtils.isNotBlank(user_id)){session = getLoginedUserSession(user_id);}String loginedIp = null;if(session!=null){loginedIp = (String)session.getAttribute(ESessionKey.LoginIP.key);//获取已登录者ip(如果有)}if(StringUtils.isNotBlank(loginedIp) && !localIp.equals(loginedIp)){MySessionContext.DelSession(session);//踢人--找到并销毁Sessionrequest.setAttribute("msg", "您的账号在其它ip登录,您被踢下线了!");request.getRequestDispatcher("/login.jsp").forward(request, response);}else{chain.doFilter(request, response);//放行}}
Session过期过滤器 核心代码
@Overridepublic void doFilter(ServletRequest req, ServletResponse resp, FilterChain chain) throws IOException, ServletException {System.out.println("过滤请求...");HttpServletRequest request = (HttpServletRequest)req;HttpServletResponse response = (HttpServletResponse)resp;//session中获取用户名信息 String userId = (String)request.getSession().getAttribute("userId"); String admin = (String)request.getSession().getAttribute("admin"); //普通用户登录过滤,如果用户名为空说明带有登录标记的Session过期了if (userId==null||"".equals(userId.toString()) ) { //超级管理员过滤if(admin==null||"".equals(admin.toString())){response.sendRedirect(request.getContextPath()+ADMIN_URL);return ;}//如果普通用户和超级管理员都没有登陆内容,说明登录过期System.out.println("登录过期,请重新登录!");response.sendRedirect(request.getContextPath()+LOGIN_URL);PrintWriter printWriter = response.getWriter();String relogin = "登录过期,请重新登录!";printWriter.write(relogin);printWriter.flush();printWriter.close();return ;}//过滤通过,放行chain.doFilter(request, response);System.out.println("过滤响应!");}
web.xml配置
<!-- 登录踢人过滤器 --><filter><filter-name>TickFronterFilter</filter-name><filter-class>com.fengyun.web.filter.TickFronterFilter</filter-class></filter><filter-mapping><filter-name>TickFronterFilter</filter-name><url-pattern>/login.html</url-pattern></filter-mapping><!-- session监听器 --><listener><listener-class> com.fengyun.web.filter.SessionCounter </listener-class></listener><!-- session过期过滤器 --><filter><filter-name>Loginfilter</filter-name><filter-class>com.fengyun.web.filter.LoginOverdueFilter</filter-class></filter><filter-mapping><filter-name>Loginfilter</filter-name><url-pattern>/material/*</url-pattern>...等等需要过滤的url地址...当然可以使用通配方式写(此处不详述)<url-pattern>/operate_editeCompact.html</url-pattern><dispatcher>REQUEST</dispatcher><dispatcher>FORWARD</dispatcher><dispatcher>INCLUDE</dispatcher><dispatcher>ERROR</dispatcher></filter-mapping>
JavaWeb-实现多ip、异地 同时登录踢人下线相关推荐
- 登录超时提示+踢人下线实现(spring security)
前言 最近,说有可能要上只允许一个地方登录,还要配合信息推送,今天有空,就起个头,把登录超时.登录踢人下线一起做了.信息推送的,后面再说,留好口子就行. 一.背景 这里是spring security ...
- java脚本封号_java中如何踢人下线?封禁某个账号后使其会话立即掉线!
需求场景 封禁账号是一个比较常见的业务需求,尤其是在论坛.社区类型的项目中,当出现了违规用户时我们需要将其账号立即封禁. 常规的设计思路是:在设计用户表时增加一个状态字段,例如:status,其值为1 ...
- java怎么封禁玩家_java中如何踢人下线?封禁某个账号后使其会话立即掉线!
需求场景 封禁账号是一个比较常见的业务需求,尤其是在论坛.社区类型的项目中,当出现了违规用户时我们需要将其账号立即封禁. 常规的设计思路是:在设计用户表时增加一个状态字段,例如:status,其值为1 ...
- java实现踢下线用户_java中如何踢人下线?封禁某个账号后使其会话立即掉线!...
需求场景 封禁账号是一个比较常见的业务需求,尤其是在论坛.社区类型的项目中,当出现了违规用户时我们需要将其账号立即封禁. 常规的设计思路是:在设计用户表时增加一个状态字段,例如:status,其值为1 ...
- java怎么实现七天封禁玩家_java中如何踢人下线?封禁某个账号后使其会话立即掉线!...
需求场景 封禁账号是一个比较常见的业务需求,尤其是在论坛.社区类型的项目中,当出现了违规用户时我们需要将其账号立即封禁. 常规的设计思路是:在设计用户表时增加一个状态字段,例如:status,其值为1 ...
- 内网穿透实现实体服务器变云服务器:服务器无公网ip,如何提供公网网站,又如何异地ssh登录或者异地登录服务器的宝塔面板
先说本经验的应用场景 up主的就业方向是开发网站前后端,有一台自己的实体服务器,没有公网IP,我希望: 能长久地提供任何人在任何地点都能用浏览器访问到的网站: 另外由于服务器存放在家里,我开学.旅游. ...
- Shiro实现session限制登录数量踢人下线
Shiro实现session限制登录数量踢人下线 前言 实现 ■ 架构准备 ShiroConfig ■ redis内的存储分布 ■ 代码修改 修改 JedisSessionDAO 修改 SystemA ...
- Linux日常之允许或禁止指定用户或IP进行SSH登录
1. 用户 SSH登录 2. IP SSH登录 暂时只了解到了hosts.allow和hosts.deny的方式,iptable方式只了解到针对端口的操作 1. 用户 SSH登录 允许特定用户登录(白 ...
- 单账户登录踢人 php,踢人下线
前言 在java的世界里,有很多优秀的权限认证框架,如Apache Shiro.Spring Security 等等.这些框架背景强大,历史悠久,其生态也比较齐全. 但同时这些框架也并非十分完美,在前 ...
最新文章
- 百度 什么是主成分分析
- matlab主成分分析散点图_matlab、R软件等做主成分分析结果不同?为什么?
- c++中有表示正无穷的数吗_阅读:贯穿编程人生CSAPP[2]信息表示
- RxSwift之深入解析场景特征序列的使用和底层实现
- 手写自己的MyBatis框架-V2.0参数处理
- oracle之set运算符和练习
- leader:你的代码太烂了我根本看不懂
- 解决FileUpload控件上传大文件被拒问题时
- linux (fedora 28) 制作启动U盘,启动盘
- 5.Knockout.Js(自定义绑定)
- mssql 数据库“查询处理器用尽了内部资源,无法生成查询计划。”问题的处理...
- c语言家谱管理系统不是二叉树,二叉树实现的简单家谱管理系统
- 带键盘的java模拟器_虚拟键盘实现!JAVA模拟器PSPKVM v0.3.2推出
- mysql fetch lengths_phpmysqli_fetch_lengths函数怎么用
- ssh publisher_3种Microsoft Publisher的开源替代品
- java获取和风天气_和风天气(一)数据分析
- RuntimeError: mat1 and mat2 shapes cannot be multiplied
- UVA 11384 Help is needed for Dexter (递归函数)
- rtf格式内容转html
- RTSP 流媒体播放地址