文档章节

利用session+application+cookie 实现单态登陆,且解决浏览器意外关闭的问题

恋佳
 恋佳
发布于 2015/07/22 14:06
字数 779
阅读 31
收藏 1

最近在帮朋友做一个购物网站,里面涉及到了登陆的问题。其中包括后台管理员的登陆和用户的登陆。

在这个网站中,设计了后台管理员单态登陆,即一个账号只能有一个登陆实例。很容易想到的就是用application实现,在application中放置一个hashmap,储存登陆的管理员信息。同时为了实现登陆超时,也在session中存放登陆对象,通过设置session的listener监控session的消亡,移除application中的对象。那么问题来了,如果用户因为断电或者任性,非法关闭了浏览器,再打开浏览器,显然application中还存在上一次的登陆对象,不能再次登陆了,这样就造成了用户永远无法登陆的问题

在网上查了一下,很多人遇到这个问题,万能的网友给的建议是用心跳包的方式,判断用户离线,但是本人觉得这样方法太过占用资源。于是有了以下这个方法。核心思想是,利用cookie保存成功登陆的sessionId,然后在application对象再增加一个hashmap,key是sessionId,value依然是管理员对象。每次打开登陆界面时,首先检查cookie,如果存在就取出sessionId,然后查看application中保存sessionId的hashmap,如果存在这个sessionId,就取出管理员信息,并放在新的session中。

PS:浏览器的session机制是这样的,每次打开浏览器服务器会为这个浏览器创建一个新的session,它的消失不受浏览器的关闭控制。而是服务器自动回收,但是如果浏览器关闭再打开,就会产生一个新的session,但并不意味着服务器中找不到上一次打开浏览器的session。所以将sessionId保存在cookie中,相当于变相在浏览器中找到上一次的session并进行操作。

源代码如下

(1) session 监听器代码


ServletContext application;

	@Override
	public void sessionCreated(HttpSessionEvent arg0)
	{
		 ServletContext application=arg0.getSession().getServletContext();
    	 HashMap<String,ManagerForm>allManagerBySessionId=( HashMap<String,ManagerForm>)application.getAttribute("allManagerBySessionId");
    	 if (null==allManagerBySessionId)
    	 {
    		 allManagerBySessionId=new HashMap<String,ManagerForm>();
    		 application.setAttribute("allManagerBySessionId",allManagerBySessionId);
    	 }
    	 System.out.println("创建");
	}

	@SuppressWarnings("unchecked")
	@Override
	public void sessionDestroyed(HttpSessionEvent arg0)
	{
		
		ManagerForm form = (ManagerForm) arg0.getSession().getAttribute("user");
		application=arg0.getSession().getServletContext();
		HashMap<String, ManagerForm>hashMap=(HashMap<String, ManagerForm>)application.getAttribute("allManager");
		
		if (hashMap!=null)
		{
			if (null!= hashMap.remove(form.getId().toString()))
			{
				System.out.println("移除");
			}
			
		}
		HttpSession session=arg0.getSession();
		HashMap<String,ManagerForm>allManagerBySessionId=( HashMap<String,ManagerForm>)application.getAttribute("allManagerBySessionId");
     	if (allManagerBySessionId.containsKey(session.getId()))
		{
     		allManagerBySessionId.remove(session.getId());
     		application.setAttribute("allManagerBySessionId",allManagerBySessionId);
		}
		
	}

(2)登陆校验页面代码

//保存SesionID至浏览器cookie
					Cookie cookie=new Cookie("user",request.getSession().getId());
					cookie.setMaxAge(3600);
					response.addCookie(cookie);
					//向特定hashMap中保存form对象
					
					HashMap<String,ManagerForm>allManagerBySessionId=( HashMap<String,ManagerForm>)appliction.getAttribute("allManagerBySessionId");
			     	
					allManagerBySessionId.put(request.getSession().getId(),userForm);

(3) 浏览器登陆页面校验代码

<%
		Cookie[] allCookies = request.getCookies();
			String savedSessionId = "";
			if (allCookies != null)
			{
				for (int i = 0; i < allCookies.length; i++)
				{
					if (allCookies[i].getName().equals("user"))
					{
						savedSessionId = allCookies[i].getValue();
						break;
					}

					
				}
			
				HashMap<String, ManagerForm> allManagerBySessionId = (HashMap<String, ManagerForm>) application
							.getAttribute("allManagerBySessionId");
					if (allManagerBySessionId.containsKey(savedSessionId))
					{
						ManagerForm form = allManagerBySessionId
								.get(savedSessionId);
						session.setAttribute("user", form);
						response.sendRedirect(request.getContextPath()+"/background/managerIndex.jsp");
						return;
					}
			}
	%>












版权声明:本文为博主原创文章,未经博主允许不得转载。

© 著作权归作者所有

共有 人打赏支持
恋佳
粉丝 0
博文 76
码字总数 62107
作品 0
大连
私信 提问
HttpSession的工作原理及相关常见问题

以下以session简称: 1、session的生命周期:session是在服务器第一次执行getSession()语句时才创建的(此方法:服务器先从浏览器带来的cookie中查找JSESSIONID,是否有相关可用的session,有...

木子丰
2015/03/13
0
0
API 接口设计中Token设计讨论

在实际的网站设计中我们经常会遇到用户数据的验证和加密的问题,如果实现单点,如果保证数据准确,如何放着重放,如何防止CSRF等等。 其中,在所有的服务设计中,都不可避免的涉及到Token的设...

董小保
2018/08/15
0
0
一个账号同时只能在同一个设备上登陆

一个账号同时只能在同一个设备上登陆 redis 我用PHP实现一个账号只能同时在同一个设备登录,注意,不是同一个IP。 之前是在MYSQL的表中加了个显示是否登录了的字段,若登录了设置为1,退出设...

蜗牛奔跑
2016/11/14
25
0
Flask: SSO原理及实现

现在大多数软件公司的业务不再是单条线,而是发展成多元化的产品线。包括多个网站应用、移动APP以及桌面软件,那么当然希望能实现统一用户和统一登录。统一用户基本都已实现,然而统一登录却...

陈亦
2014/02/15
0
25
cookie+memcached实现单点登陆

10年的时候在iteye的第一篇文章记录了一下当时怎么实现我们系统的单点登陆。不过那个时候文章写的不好,思路也很浮躁,很难看懂,在csdn的第一篇技术博客打算重新温顾一下当时实现单点登陆的...

吞吞吐吐的
2017/10/18
0
0

没有更多内容

加载失败,请刷新页面

加载更多

AWS的自动部署工具codedeploy 负载均衡器和github

Elastic Load Balancing 提供了三种可用于 CodeDeploy 部署的负载均衡器:Classic Load Balancer、Application Load Balancer 和 Network Load Balancer。 传统负载均衡器 路由和负载均衡在传...

守护-创造
25分钟前
3
0
Docker 使用简介

Docker 是使用 GoLang 开发的开源容器引擎,可以方便的打包开发好的应用,然后分发到任意 linux 主机上。 与传统的虚拟机相比拥有以下优势: 高效的系统资源利用率 由于不需要进行硬件虚拟和...

YanWen
28分钟前
2
0
linux多线程编程,你还在用sleep么?用pthread_cond_timedwait吧

gnal(&cond); pthread_mutex_unlock(&mutex); printf(“Wait for thread to exit\n”); pthread_join(thread, NULL); printf(“Bye\n”); return 0; } 说明(翻译摘要中提供的连接,翻译的不好......

shzwork
36分钟前
1
0
MacOS源码编译安装 PostgreSQL

编译环境 Mac OSX 下只要装了 Xcode 就行,所有编译需要的工具和类库都有了。CentOS 下需要安装下面的软件包。 $ sudo yum install make gcc readline-devel zlib-devel flex bison 如果是从...

FeanLau
46分钟前
2
0
Spring Cloud Alibaba基础教程:Sentinel使用Apollo存储规则

上一篇我们介绍了如何通过Nacos的配置功能来存储限流规则。Apollo是国内用户非常多的配置中心,所以,今天我们继续说说Spring Cloud Alibaba Sentinel中如何将流控规则存储在Apollo中。 使用...

程序猿DD
53分钟前
1
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部