java限制在同一台电脑上只允许有一个用户登录系统

在web应用系统中,出于安全性考虑,经常需要对同一客户端登录的用户数量和一个客户同时在多个客户端登陆进行限制。

具体一点就是:

1、在同一台电脑上一次只允许有一个用户登录系统;

2、一个用户在同一时间只允许在一个客户端登录。

我最近做的一个系统就遇到了这样的问题,本来系统已经开发完成了,但是安全测评没有通过,就是因为没有做这两个限制。怎么来做这样的限制呢?我在网上找了很久,发现问这个问题的人很多,但是没有找到特别清楚的答案。后来自己摸索着,看了一些书,终于找到解决办法了。

要解决这个问题实际上不难,对于高手来说可能都懒得去说了,但是对于不熟悉web编程的人来说可能会困扰很久。下面我把我的解决办法说出来,供大家参考!

先介绍一下我那个系统的背景:j2ee,tomcat,没有用cookie。

首先确定解决这两个问题的基本思路:

1、要解决同一台电脑上只允许有一个用户登录系统,只有一个办法。监视每一个连接的来源,如果发现有一个新的连接与某个已经存在的连接来自同一台电脑,则终止其中的一个(当然,也可以提醒用户,让他自己决定终止哪一个)。

2、要禁止一个用户账号同时在不同的客户端登录,只有监视每一个连接的用户账号,如果发现一个新连接的用户账号跟某个已经存在的连接的用户账号相同,则自动将前一个终止(同样,也可以让用户自己决定终止哪一个)。

确定了基本思路以后,就要找具体办法了。我最初的想法是在数据库建立一张表,存放已登录用户的用户名、物理地址、Session id等信息。当用户登录时,与这张表里面的数据进行匹配,如果发现物理地址与表中的某条记录相同,则表示是同一台客户端上有多个用户再登录,如果发现正在登录的用户的用户名与表中已有记录相同而主机名不同,则表示是一个账号同时在不同的客户端使用。

相信很多一开始遇到这个问题的人都会考虑这种解决办法。但是这种办法有很多问题,最主要的问题有两个:第一是效率,每一次都要从数据库里面取数据进行匹配。第二是用户退出时需要删除表中的记录,而当用户非正常退出时,很难及时监测(后来发现其实有办法监测)。

后来在网上的某个帖子里面看到一位大侠提到用监听器,只是那位大侠说的太含糊,照他说的办法根本无法解决。虽然无法解决,但是提供了一个思路。于是我找了一本书,仔细看了其中关于监听器的部分。解决办法就在其中了!!!

监听器的详细介绍见我的下一篇博文,这里先把解决办法告诉大家:

监听器可以监听Session及其所包含的属性,即Attribute。

所以我们要做的就是:

1、建立一个监听器,实现HttpSessionAttributeListener接口,监听每一个Attribute的增加、编辑、删除事件。监听器中还要建立一个map,将所有的session放入这个map中。

2、在用户登录时将用户名、物理地址、Session id存到Session中去(可以建立一个用户登录地址数据传输对象,我建立了一个UserSessionAdd类,里面包含username,macAdd,sessionId三个属性,用户登录时将这个数据对象初始化,并存入到session中)。

3、每个新会话开启时,在监听器中对Session包含的属性进行判断,如果新增的属性与map中已有session的用户登录地址数据相同,则表示新会话与我们要做的两个限制相冲突。将与之冲突的会话提取出来,销毁掉!

这么说,还是不够清楚,下面看代码:

Web.xml文件:
03.<listener>  
04.  
05.       <listener-class>监听器类的路径,如:com.web.MyListener</ listener-class >  
06.  
07.</listener>  


用户登录地址数据传输对象:

01.public class UserSessionAdd {  
02.  
03.  
04.private Stringadd;  
05.  
06.  
07.private Stringsessid;  
08.  
09.  
10.private String username  
11.  
12.public String getUsername(){  
13.  
14.return username  
15.  
16.}  
17.  
18.Public void setUsername(String username){  
19.  
20.       this.username=username;  
21.  
22.    }  
23.  
24.public String getIp() {  
25.  
26.returnadd;  
27.  
28.}  
29.  
30.publicvoid setAdd(String add) {  
31.  
32.this.add = add;  
33.  
34.}  
35.  
36.public String getSessid() {  
37.  
38.returnsessid;  
39.  
40.}  
41.  
42.publicvoid setSessid(String sessid) {  
43.  
44.this.sessid = sessid;  
45.  
46.}  
47.  
48.  
49.}  

用户登录的代码:

03.String userHost = request.getRemoteHost();  
04.  
05.String sessionId = request.getSession().getId();  
06.  
07.UserSessionAdd usa = new UserSessionAdd();  
08.  
09.usa.setUsername(username);  
10.  
11.usa.setSessid(sessionId);  
12.  
13.usa.setAdd(userHost);  
14.  
15.request.getSession().setAttribute(“usa”,usa);  


监听器代码:

01.publicclass MyListenerimplementsHttpSessionAttributeListener{  
02.  
03.  
04.Map<String, HttpSession> map =new HashMap<String, HttpSession>();  
05.  
06.publicvoidattributeAdded(HttpSessionBindingEvent event) {  
07.  
08.String name = event.getName();  
09.  
10.if(name.equals("usa")){  
11.  
12.UserSessionAdd usa = (UserSessionAdd)event.getValue();  
13.  
14.if(map.get(usa.getAdd())!=null){  
15.  
16.HttpSession sess = map.get(usa.getAdd());  
17.  
18.UserSessionAdd usa1 = (UserSessionAdd)sess.getAttribute("usa");  
19.  
20.sess.removeAttribute("usa");  
21.  
22.sess.invalidate();  
23.  
24.}  
25.  
26.map.put(usa.getAdd(), event.getSession());  
27.  
28.}  
29.  
30.}  
31.  
32.  
33.publicvoidattributeRemoved(HttpSessionBindingEvent event) {  
34.  
35.String name = event.getName();  
36.  
37.if(name.equals("usa")){  
38.  
39.UserSessionAdd usa = (UserSessionAdd)event.getValue();  
40.  
41.map.remove(usa.getAdd());  
42.  
43.}  
44.  
45.}  
46.  
47.  
48.publicvoidattributeReplaced(HttpSessionBindingEvent event) {  
49.  
50.// TODO Auto-generated method stub  
51.  
52.````  
53.  
54.}  
55.  
56.}  


转自:http://blog.csdn.net/yutan_313/article/details/5405934


本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.mzph.cn/news/443843.shtml

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈email:809451989@qq.com,一经查实,立即删除!

相关文章

Matplotlib——绘制图表

文章目录通过figure()函数创建画布通过subplot()函数创建单个子图通过subplots()函数创建多个子图通过add_subplot()方法添加和选中子图添加各类标签绘制常见图表绘制直方图——hist()函数绘制散点图——scatter()函数绘制柱状图——bar()函数设定线条的相关参数本地保存图片通…

限制在同一台电脑上只允许有一个用户登录系统

在web应用系统中&#xff0c;出于安全性考虑&#xff0c;经常需要对同一客户端登录的用户数量和一个客户同时在多个客户端登陆进行限制。 具体一点就是&#xff1a; 1、在同一台电脑上一次只允许有一个用户登录系统&#xff1b; 2、一个用户在同一时间只允许在一个客户端登录…

Seaborn——绘制统计图形

文章目录可视化数据的分布绘制单变量分布绘制双变量分布绘制成对的双变量分布用分类数据绘图类别散点图通过stripplot()函数画散点图swarmplot()函数类别内的数据分布绘制箱型图绘制提琴图类别内的统计估计绘制条形图绘制点图可视化数据的分布 绘制单变量分布 一般采用最简单…

Bokeh——交互式可视化库

文章目录前言如何通过Plotting绘制图形前言 Bokeh是一个专门针对Web浏览器使用的交互式可视化库&#xff0c;这是与其他可视化库相比最核心的区别。 如何通过Plotting绘制图形 Plotting是以构建视觉符号为核心的接口&#xff0c;可以结合各种视觉元素&#xff08;例如&#x…

指针、引用以及const限定符、constexpr限定符

文章目录复合类型引用概念与使用引用的定义注意指针概念声明方式取地址符指针值空指针利用指针访问对象赋值和指针void* 指针指向指针的指针指向指针的引用初始化所有指针有多重含义的某些符号const限定符概念const的引用指针和const顶层const和底层constconstexpr和常量表达式…

关键字typedef、关键字using、auto类型说明符和declytpe类型指示符

文章目录类型别名概念关键字 typedef别名声明 (alias declaration) using指针、常量和类型别名类型别名简化多维数组指针auto类型说明符概念复合类型、常量和autodecltype类型指示符概念decltype和引用类型别名 概念 有两种方法可用于定义类型别名。 关键字 typedef typede…

初始化、赋值、默认初始化、列表初始化、类内初始值、直接初始化与拷贝初始化

文章目录初始化和赋值的区别什么是默认初始化&#xff1f;列表初始化列表初始化的使用场景不适合使用列表初始化的场景类内初始值混用string对象和C风格字符串数组与vector对象关于vector对象两者间的初始化关系直接初始化与拷贝初始化初始化和赋值的区别 初始化的含义是创建变…

js动态增加,删除td,tr,table,div

js实现的动态添加&#xff0c;删除table内容&#xff1a; 截图如下&#xff1a; 1. 2. 源代码&#xff1a; main.css body {background-image: url(../images/qiantai/bg.png);font-family: arial;font-size: 12px;color: #d4d7da;text-align: center;background-repeat: r…

string类的相关知识及部分操作

文章目录string对象的初始化string::size_type类型string对象的读写操作使用标准库中的iostream使用getline读取一整行string对象的比较操作string对象的相加操作两个string对象相加字面值和string对象相加string对象的初始化 拷贝初始化(copy initialization)&#xff1a;使用…

数组的部分练习

3.27&#xff1a;假设txt_size是一个无参数的函数&#xff0c;它的返回值是int。请回答下列哪个定义是非法的&#xff1f;为什么&#xff1f; unsigned buf_size1024; &#xff08;a&#xff09;int ia[buf_size];  &#xff08;b&#xff09;int ia[4*7-14]; &#xff08…

关于范围for语句的使用

文章目录使用范围for语句处理多维数组使用范围for语句处理多维数组 举个例子&#xff0c;使用范围for语句输出多维数组&#xff08;ia&#xff09;所有值&#xff1a; for (const auto &row : ia)for (auto col : row)cout << col << endl;本循环中并没有任何…

vector的应用练习

文章目录编写一段程序&#xff0c;使用条件运算符从vector< int >中找出哪些元素的值是奇数&#xff0c;然后将奇数值翻倍。 #include <iostream> #include <ctime> #include <vector> using namespace std; typedef int int_array[4]; int main() {v…

sizeof运算符运算结果小汇

文章目录sizeof运算符的结果部分地依赖于其作用的类型sizeof运算符的结果部分地依赖于其作用的类型 对char或者类型为char的表达式执行sizeof运算&#xff0c;结果得1对引用类型执行sizeof运算得到被引用对象所占空间的大小对指针执行sizeof运算得到指针本身所占空间的大小对解…

jQuery实现复选框的全选和反选:

jQuery实现复选框的全选和反选&#xff1a; 截图如下&#xff1a; 代码如下&#xff1a; index.jsp: <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <%String path request.getContextPath();String basePath…

C语言隐式/显式类型转换 | C++四种强制类型转换、类的隐式转换、explicit

文章目录C语言类型转换隐式类型转换显式类型转换C 强制类型转换static_castreinterpret_castconst_castdynamic_cast类的隐式类型转换概念只允许一步类类型转换explicit 抑制构造函数定义地隐式转换可以通过显式转换使用explicit构造函数C语言类型转换 隐式类型转换 编译器在…

string对象和C风格字符串

混用string对象和C风格字符串 我们都知道允许使用字符串字面值来初始化string对象&#xff1a; string s("Hello World!");C规定&#xff0c;任何出现字符串字面值的地方都可以用以空字符结束的字符数组来替代&#xff1a; 允许使用以空字符结束的字符数组来初始化…

函数重载、引用再探、内联函数

文章目录函数重载为什么C支持重载&#xff0c;C语言不支持呢&#xff1f;extern “C”引用再探引用的特性引用的使用场景引用和指针引用和指针的不同点:内联函数什么是内联函数&#xff1f;内联函数的特性内联函数的好处类的内联成员函数的声明内联函数的使用constexpr函数概念…

类的概念、成员函数的定义方式、类的访问控制和封装、类的大小、this指针

文章目录类的概念structclassclass和struct的区别是什么呢&#xff1f;类中成员函数的两种定义方式声明和定义都在类中声明和定义分离类的访问控制和封装类的封装特性类的大小结构体内存对齐规则类的存储方式this指针类的概念 在C中&#xff0c;类可以说是最重要的东西&#x…

jQuery实现两个列表框的值之间的互换:

jQuery实现两个列表框的值之间的互换&#xff1a; 截图如下&#xff1a; 代码如下&#xff1a; <% page language"java" import"java.util.*" pageEncoding"UTF-8"%> <%String path request.getContextPath();String basePath reque…

类的6个默认成员函数:构造函数、析构函数、拷贝构造函数、重载运算符、三/五法则

文章目录6个默认成员函数构造函数概念默认构造函数的类型默认实参概念默认实参的使用默认实参声明全局变量作为默认实参某些类不能依赖于编译器合成的默认构造函数第一个原因第二个原因第三个原因构造函数初始化构造函数里面的“”是初始化吗&#xff1f;为什么要使用列表初始化…