有关于同一时间用户只能在一个地方登录的问题
以下内容可能将的有点罗嗦,思路或者不清晰,请各位高手手下留情,肯定有更好的方法了,各位高手如果有的话,可否分享一下,谢谢!
1.在服务器,用户每次登录session都不一致,但是session内容中的登录信息或许一致,但是这里还存在一个时间差,如何判断同一个用户在别的地方登录呢
可以比对时间,根据时间大小来判断,当然时间大的就需要留下来了,小的自然就需要删除了
这时候又出现一个问题,你如何知道服务器session中那些session是同一个用户的呢,所以自然需要保持同一个用户的session在服务器最好是唯一.
首先需要有个地方保存session,不管你登录几次,都可以保存在这里,这里只是说的登录,如果要做其他操作,那么最后登录的肯定是没问题的,但是其他登录的就会提示”此用户已在其他地方登录”
现在说说保存session的地方,我使用的是hashmap<用户名,hashmap<时间,session>>,但是使用时间比较复杂,可以简化一下,使用用户登录次数,这个数值也是处于一直变大的情况中.那么保存的数据就变成hashmap<用户名,hashmap<登录次数,session>>
那么现在假设一下存session的地方也是hashmap,假设为A
那么同一个用户第一次登录都会发生
HashMap b=new HashMap();
B.put(1,session对象);
A.put(“admin”,b)
第二次登录
HashMap b=new HashMap();
B.put(2,session对象);
A.put(“admin”,b)
第三次登录
HashMap b=new HashMap();
B.put(3,session对象);
A.put(“admin”,b)
现在用户admin在不同的地方登录了三次。
按我们的需求来说,前两次在有其他操作就会提示”此用户已在其他地方登录”
当然第一次的登录和第二次的登录后的操作完全是独立开来的,就是说第一次登录和第二次登录后再有其他操作都会提示”此用户已在其他地方登录”,不分顺序先后,而第三次就没有影响啦,因为第三次是最后登录的,当然不会有影响的.
现在该说说如何让第一次和第二次登录后的操作提示”此用户已在其他地方登录”了
首先该有拦截器,拦截器中怎么判断呢,肯定是根据用户名来判断了,因为我们存session的地方就是用用户名当做标示来存的,如果有,是不是该将这个session删除掉呢,删除掉以后提示
”此用户已在其他地方登录”,页面刷新,是不是页面就再次处于未登陆的情况呢.
比较简单吧,我在当时做的时候下了功夫不少,主要是怎么保存session,session里保存什么,经过几次考虑以及不少的测试才决定先将session和登陆次数保存在hashmap中,在将hashmap和用户名保存在hashmap中,肯定还有其他办法的.
下面说说怎么比较hashmap中的数据吧
上面已经说过 A(保存用户名和hashmap b的地方)
如果当前登陆用户如果在A不存在,那么需要添加
如果存在,那么是不是该比较里面的hashmap了呢
这里还有一个问题,只有一个用户登录的时候,也会经过过滤器,那么需要当前用户名在A中的数量必须大于1了
大于一就要开始循环了,这里的时候就发现怎么循环呢,我使用迭代和while比较合适,
首先你需要全部将A中某用户的信息循环一遍,根据当前操作的sessionid和B(B是保存在A中hashmap)是否一致,一致的话将B中的key取出来,也就是我们存在的登录次数.
在一次循环是不是该判断取出的key和B中的可以比大小了,取出的key必须是小于B中存放的key,才能够删除的,这里不需要标示一下,如果小于,立马停止循环,
第三次开始对比了,上面已经标示了是否小于B中的key了,如果标示成立,那么循环中就需要比较一致的key了,找到了就可以删除了,当然删除了自己,同时要将session清除掉,这样是不是就可以了呢.
以下是部分代码
获取登录次数
int dates=webUserManager.get_login_num(result.get("CH").toString());
MySessionMapClass.replaceSession(request.getSession(),result.get("CH").toString(),dates);
比对类
public class MySessionMapClass {
private static Map onlineSessionMap = new HashMap();// 已登录的会话列表
public static boolean replaceSession(HttpSession newSession, String kskh,int dates) {
boolean flag = false;
if (onlineSessionMap.containsKey(kskh)) {
//获取ch对应的hashmap
HashMap newHms=(HashMap)onlineSessionMap.get(kskh);
newHms.put(dates,newSession);
onlineSessionMap.put(kskh, newHms);
flag = true;
} else {
// 如果会话列表中不包含该会话,则添加
HashMap hms=new HashMap();
hms.put(dates,newSession);
onlineSessionMap.put(kskh, hms);
flag = false;
}
return flag;
}
/**
* 比较新会话和旧会话的ID,如果ID相同,则表示是同一个用户,返回true
*
* @param session
* @param kskh
* @return boolean ID相同返回true,
*/
public static boolean isSameSession(HttpSession newSession, String kskh) {
boolean flag = false;
HashMap maps = new HashMap();
try {
// 获得旧会话
maps = (HashMap) onlineSessionMap.get(kskh);
if(maps!=null){
if(maps.size()>1){
//因为MAP中存储的键是日期时间字符串 值是session对象 留下最大的日期字符串 删除其他的session
String dates="";
//找出session对应的日期字符串
Iterator it = maps.entrySet().iterator();
while(it.hasNext()){
java.util.Map.Entry entry = (java.util.Map.Entry)it.next();
String keys= entry.getKey().toString();// 返回与此项对应的键
HttpSession values= (HttpSession)entry.getValue(); //返回与此项对应的值
if(newSession.getId().equals(values.getId())){
dates=keys;
}
}
Iterator it1 = maps.entrySet().iterator();
while(it1.hasNext()){
java.util.Map.Entry entry = (java.util.Map.Entry)it1.next();
String keys= entry.getKey().toString();// 返回与此项对应的键
HttpSession values= (HttpSession)entry.getValue(); //返回与此项对应的值
if(Integer.parseInt(dates)<Integer.parseInt(keys)){
flag=true;
break;
}else{
}
}
Iterator it2 = maps.entrySet().iterator();
while(it2.hasNext()){
java.util.Map.Entry entry = (java.util.Map.Entry)it2.next();
String keys= entry.getKey().toString();// 返回与此项对应的键
HttpSession values= (HttpSession)entry.getValue(); //返回与此项对应的值
if(flag==true){//删除自己
if(dates.equals(keys)){
maps.remove(keys);
values.invalidate();
}
}else{//删除别人
//if(!dates.equals(values)){
//maps.remove(keys);
//values.invalidate();
//}
}
}
}else{
flag=false;
}
}
} catch (Exception e) {
flag=false;
}
return flag;
}public static boolean isSession(HttpSession newSession, String kskh) {
boolean flag = false;
HashMap maps = new HashMap();
try {
// 获得旧会话
maps = (HashMap) onlineSessionMap.get(kskh);
if(maps!=null){
if(maps.size()>1){
flag=true;
}
}
} catch (Exception e) {
flag=false;
}
return flag;
}
/**
*
*/
public static void delSessionFromMap(String kskh){
if(onlineSessionMap.get(kskh)!=null){
onlineSessionMap.remove(kskh);
}
}
public static boolean containKey(String kskh){
return onlineSessionMap.containsKey(kskh);
}
}
过滤器
public void doFilter(ServletRequest request, ServletResponse response,
FilterChain chain) throws IOException, ServletException {
HttpServletRequest requestMy=(HttpServletRequest)request;
HttpServletResponse responseMy=(HttpServletResponse)response;
String requesetUrl=requestMy.getRequestURI();
System.out.println("================================");
if(requestMy.getSession()!=null&&requestMy.getSession().getAttribute("CH")!=null&&requesetUrl.indexOf(".jsp")>-1){
HttpSession session=requestMy.getSession();
//判断是否在登录状态
System.out.println("+++++++++++++++++++++++++++");
if(MySessionMapClass.isSession(session,requestMy.getSession().getAttribute("CH").toString())){
boolean flag=MySessionMapClass.isSameSession(session,requestMy.getSession().getAttribute("CH").toString());
//提示已在异地登陆
System.out.println("----------------------"+flag);
if(flag){
//获取不限制异地登陆的账号
//questMy.getSession().getAttribute("CH")
CommonService CommonService = (CommonService) this.getBean("commonService");
Map parameter=new HashMap();
parameter.put("CH", requestMy.getSession().getAttribute("CH").toString());
Map result = (Map) CommonService.queryForObject("get_code_fliter_login.select",parameter);
if(result!=null){
System.out.println("测试会员===========================");
if(result.get("CH")!=""&&result.get("CH").equals(requestMy.getSession().getAttribute("CH").toString())){
chain.doFilter(requestMy, responseMy);
}
}else{
System.out.println("---=======================-------"+flag);
response.setContentType("text/html;charset=UTF-8");
response.getWriter().write("<script type=\"text/javascript\">alert('您的账户已经在别处登录!');window.location.reload();</script>");
}
}else{
chain.doFilter(requestMy, responseMy);
}
}else{
chain.doFilter(requestMy, responseMy);
}
}else{
chain.doFilter(requestMy, responseMy);
}
}
<!--EndFragment-->
相关推荐
最近做了企业项目,其中有这样的需求要求同一帐号同一时间只能一个地点登陆类似QQ登录的功能。下面小编通过本文给大家分享实现思路,感兴趣的朋友参考下吧
NULL 博文链接:https://lihao312.iteye.com/blog/1909205
方法二:图斑之间有小的缝隙,可以先在缝隙上任意补画一个图斑,然后合并(merge)图斑,最后再剪切(Clip)即可得到无缝的图斑。 如下图所示: 24.利用两个相交图斑创建新图斑。 两个图斑都选中然后 Eidtor 工具...
VLAN是为解决以太网的广播问题和安全性而提出的一种协议,它在以太网帧的基础上增加了VLAN头,用VLAN ID把用户划分为更小的工作组,限制不同工作组间的用户互访,每个工作组就是一个虚拟局域网。虚拟局域网的好处...
一个Servlet只能运行在一个Servlet环境中,但是不同的Servlet可以在Servlet引擎上有不同的视图。 如果Servlet引擎支持虚拟主机,每个虚拟主机有一个Servlet环境。一个Servlet环境不能在虚拟主机之间共享。 Servlet...
我们可能还会遇到另外一个问题,即当用户的口令为空时,即使你做了上述的所有的更改还是不能进行登录,访问还是会被拒绝。这是因为,在系统“安全选项”中有“账户:使用空白密码的本地账户只允许进行控制台登录”...
图 5 进程和线程的关系 进程可以是单线程也可以是多线程的,单线程进程同一时间只能在一个核心上执行 ,其性能取决于核心本身,而多线程进程同一时间可在多个核心上执行,因此它的性能 就超越了单一核心上的性能...
修正同一页面存在多个播放器时只能播放一个的问题 新增 RSS2.0的导入和导出 XML-RPC 远程发布功能(MetaWeblog API) 可以自定义时间格式(留言,评论,日志) 可以开启/关闭Blog,并可以设定Blog关闭原因 后台菜单...
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。 20、abstract class和interface有什么区别? ...
系统只能允许一个程序运行 7 在状态栏中添加时间 8 研究调用存储过程 8 得到本机的IP地址 9 vc调用chm文件 10 最高窗口的实现 10 防止Edit框中的Password不保密 11 在同一系统中显示GB字符和BIG5字符 12 改变颜色...
系统只能允许一个程序运行 7 在状态栏中添加时间 8 研究调用存储过程 8 得到本机的IP地址 9 vc调用chm文件 10 最高窗口的实现 10 防止Edit框中的Password不保密 11 在同一系统中显示GB字符和BIG5字符 12 改变颜色...
当应用程序在对象上调用了一个需要花费很长时间来执行的方法,并且不希望让程序等待方法的返回时,就应该使用异步编程,在很多情况下采用异步途径往往更有效率。 17、abstract class和interface有什么区别? 声明方法...
1.24 我在一个文件中定义了一个extern数组,然后在另一个文件中使用,为什么sizeof取不到数组的大小? 13 声明问题 14 1.25 函数只定义了一次,调用了一次,但编译器提示非法重声明了。 14 *1.26 main的正确...
l 组内合作——在缺省的情况下,一般一个文件在某一时间只允许一个用户对其进行修改,这样可以防止文件意外地被其他用户改动或者覆盖。但管理员可以改动这种缺省的设置,允许文件多层签出。这种设置也能防止过多的、...
·创建一个证书,并有一个值得信赖的权威,积极找出真正的最终用户,您的服务器的签署。 SFTP以上的SSH2: ·安全地传输文件,使用防火墙友好的SFTP协议。创建一个4096位的私钥和定制提供最大的安全性的密码和互助...
o 7.1 我在一个源文件中定义了 char a[6], 在另一个中声明了 extern char *a 。为什么不行 ? o 7.2 可是我听说 char a[ ] 和 char *a 是一样的。 o 7.3 那么, 在 C 语言中 ``指针和数组等价" 到底是什么意思 ? ...
近日在CDB并行测试中发现一个问题:我们需要的小区负荷话统结果总是为零,开始还以为小区负荷太小,于是加大短消息下发数量,但还为零,于是在程序中加入测试代码,把收到的数据在BAM上打印出来, 结果打印出来的...
8 c6 p0 N( J1 o域控制器就是存储活动目录的地方,一个域可以有一个或几个域控制器。在域中,各域控制器相互复制活动目录的改变,在目录林中,各域控制器相互之间也把信息自动复制给对方。 $ j D* X9 F, S$ @ X1 Q+ ...
1.24 我在一个文件中定义了一个extern数组,然后在另一个文件中使用,为什么sizeof取不到数组的大小? 声明问题 1.25 函数只定义了一次,调用了一次,但编译器提示非法重声明了。 *1.26 main的正确定义是什么...