本文主要是介绍java web 用户单点登录的方案的基本实现,希望对大家解决编程问题提供一定的参考价值,需要的开发者们随着小编来一起学习吧!
首先,考虑不能重复登录的问题。在项目中,我使用session来存储用户的信息,用户登录时,创建一个session,将用户名,用户逻辑Id,登录时间等属性存放到该session中。考虑使用Application来实现禁止重复登录。定义一个Map<Long,String>类型的变量loginUserMap。其每条记录存储登录用户的逻辑Id和对应session的sessionId。这样,每次用户登录的时候遍历loginUserMap,如果没有对应的userlogicId或sessionId则允许登录,否则提示已在别处登录。
-
- isloginexists = false;
- ifsessioninvalidate = false;
- loginUserMap = (Map<Long, String>) acx.getApplication().get(WebConstant.LOGIN_USER_MAP);
- if (loginUserMap == null) {
- loginUserMap = new HashMap<Long, String>();
- }
- HttpServletRequest request = ServletActionContext.getRequest();
- String sessionId = request.getSession(false).getId();
- System.out.println("sessionId" + sessionId);
- for (Long userlogicId2 : loginUserMap.keySet()) {
- if (!userlogicId2.equals(userlogicId) && !loginUserMap.containsValue(sessionId)) {
- continue;
- }
-
- if(userlogicId2.equals(userlogicId)&&!loginUserMap.containsValue(sessionId)){
- setIfsessioninvalidate(true);
- }
- isloginexists = true;
- break;
- }
- if (isloginexists) {
- setTip("loginexists");
- if(ifsessioninvalidate==true){
- request.getSession(false).invalidate();
- }
-
- } else {
-
- loginUserMap.put(userlogicId, sessionId);
- acx.getApplication().put(WebConstant.LOGIN_USER_MAP,loginUserMap);
- acx.getSession().put(WebConstant.USER_ID, getUsername());
- acx.getSession().put(WebConstant.USER_LOGICID,userManageService.findbyUsername(getUsername()).getLogicId());
- acx.getSession().put(WebConstant.LOGIN_TIME, new Date());
- }
在用户退出的操作中,将loginUserMap中对应的用户logicId和sessionId清除,同时清除session中的用户信息。
- Map<Long, String> loginUserMap = (Map<Long, String>)acx.getApplication().get(WebConstant.LOGIN_USER_MAP);
- String username=userManageService.findByLogicId(userlogicId).getUserName();
- if(loginUserMap.containsKey(userlogicId)){
- loginUserMap.remove(userlogicId);
- }
- session.getServletContext().setAttribute("loginUserMap", loginUserMap);
-
- Long id=(Long) session.getAttribute(WebConstant.USER_LOGICID);
- if(id!=null)
- this.userManageService.userLogout(id);
-
- session.removeAttribute(WebConstant.USER_ID);
- session.removeAttribute(WebConstant.USER_LOGICID);
- session.removeAttribute(WebConstant.LOGIN_TIME);
-
-
- session.invalidate();
-
- response.setHeader("Cache-Control","no-cache");
- response.setHeader("Cache-Control","no-store");
- response.setDateHeader("Expires", 0);
-
在session失效的监听器处理中,也做相同的操作,保证登录session超时时从loginUserMap中删除该用户,以保证后继账号能够正常登录。
- public class SessionListener implements HttpSessionListener{
-
- @Override
- public void sessionCreated(HttpSessionEvent event) {
-
- }
-
-
- @Override
- public void sessionDestroyed(HttpSessionEvent event) {
-
- HttpSession session=event.getSession();
- ServletContext application=session.getServletContext();
-
- try{
- String username=(String) session.getAttribute(WebConstant.USER_ID);
- Long userlogicId=(Long)session.getAttribute(WebConstant.USER_LOGICID);
- Map<Long, String> loginUserMap = (Map<Long, String>)application.getAttribute(WebConstant.LOGIN_USER_MAP);
- if(loginUserMap.containsKey(userlogicId))
- loginUserMap.remove(userlogicId);
- application.setAttribute(WebConstant.LOGIN_USER_MAP, loginUserMap);
- System.out.println("session:"+session.getId()+"已失效");
- }
- catch(Exception e){
- System.out.println(e.getMessage());
- }
- }
-
-
- }
到这里,基本能做到限制用户的重复登录了,但是靠这些异常情况依然无法处理,如用户使用过程中关闭浏览器,再次登录时,由于信息记录在服务器端的application中且未按照正常安全退出流程执行,则执行登录操作会提示"已在别处登录"。要解决这个问题,如下:
二、
1.在mainframe页面绑定jQuery的beforeunload事件,在关闭浏览器时执行退出程序
- $(function() {
- console.log("daemon");
- $(window).bind('beforeunload', function() {
-
- $.ajax({
- url : "logout.action",
- type : "post",
- success : function() {
- messagebox.alert("退出","您已成功登出!");
- }
- });
- });
- });
这种做法确实能实现关闭浏览器实现用户退出的功能,不过通过查阅jquery手册,发现beforeunload事件监听的不仅仅是浏览器的关闭,同时,页面的刷新操作以及页面的重定向均可导致此事件的发生,显然这些操作我们并不希望执行退出操作,我做了一些尝试,在页面中判断beforeunload监听的是哪一种操作,以达到只监听浏览器关闭的事件,不过经过多次尝试,发现各个浏览器的兼容性差异太大,只得作罢。
2.设置"心跳信号"。也就是在页面中设置一个隐藏的iframe,定时地发送请求到服务器(如每隔10s),如果一定时间内服务器没有响应(如30s),则判定用户已退出,执行登出程序。这种做法能有效监听各种异常事件,并在短时间内做出相应的处理。但是由于页面会一直不停的发送请求到服务器,如果用户量变大的时候,则服务器的压力也随之增大,这时候这种方法则不是一个比较好的解决方案。
3.由于上述两种方案均有着较大的缺陷,想到第三种方法。这种方法和第一种方法从大体思路上是类似的,即用beforeunload事件监听,但是判断是哪种操作放在服务器端。考虑到beforeunload事件监听的是离开页面的事件,关闭页面或浏览器操作为直接离开,而重定向和刷新是由离开当前页面和重新加载页面两步组成,于是我们可以考虑用session的getLastAccessedTime()方法来加以区分,getLastAccessedTime()能获取session的最后访问时间,对于关闭浏览器操作,一旦监听到执行logout 程序则最后访问事件就是关闭浏览器时的时间,而刷新和重定向操作的最后访问时间为重新加载当前页面的时间,这样便可以加以区分这两种操作。
Code:
- <pre name="code" class="java">public String logOut() throws Exception
- {
- HttpSession session = request.getSession(true);
- ActionContext acx=ActionContext.getContext();
- try{
- long lastAccessedTime1=session.getLastAccessedTime();
- Thread.sleep(2000);
- long lastAccessedTime2=session.getLastAccessedTime();
- System.out.println(lastAccessedTime1);
- System.out.println(lastAccessedTime2);
- if(lastAccessedTime1!=lastAccessedTime2)
- return NONE;
- }catch(IllegalStateException e){
- return NONE;
- }
-
-
-
- try{
- Map<String, String> loginUserMap = (Map<String, String>)acx.getApplication().get(WebConstant.LOGIN_USER_MAP);
- String username=(String)session.getAttribute(WebConstant.USER_ID);
-
- if(loginUserMap.containsKey(username)){
- loginUserMap.remove(username);
- }
- session.getServletContext().setAttribute("loginUserMap", loginUserMap);
-
-
- Long id=(Long) session.getAttribute(WebConstant.USER_LOGICID);
- if(id!=null)
- this.userManageService.userLogout(id);
-
- session.removeAttribute(WebConstant.USER_ID);
- session.removeAttribute(WebConstant.USER_LOGICID);
- session.removeAttribute(WebConstant.LOGIN_TIME);
-
- session.invalidate();
-
- response.setHeader("Cache-Control","no-cache");
- response.setHeader("Cache-Control","no-store");
- response.setDateHeader("Expires", 0);
-
- }catch(NullPointerException e){
-
- }
- return NONE;
- }
而对于浏览器崩溃,断网等异常情况,只能通过session失效时的监听器进行处理 。这里监听器的作用在于当session超时的时候,删除loginUserMap中的用户信息,这样当达到session失效的时间以后同时清除已登录的用户的信息。
Code:
- public class SessionListener implements HttpSessionListener{
-
- @Override
- public void sessionCreated(HttpSessionEvent event) {
-
- }
-
-
- @Override
- public void sessionDestroyed(HttpSessionEvent event) {
-
- HttpSession session=event.getSession();
- ServletContext application=session.getServletContext();
- try{
- String username=(String) session.getAttribute(WebConstant.USER_ID);
- Map<String, String> loginUserMap = (Map<String, String>)application.getAttribute(WebConstant.LOGIN_USER_MAP);
- if(loginUserMap.containsKey(username))
- loginUserMap.remove(username);
- application.setAttribute(WebConstant.LOGIN_USER_MAP, loginUserMap);
- }
- catch(Exception e){
- System.out.println(e.getMessage());
- }
- }
-
- }
这篇关于java web 用户单点登录的方案的基本实现的文章就介绍到这儿,希望我们推荐的文章对编程师们有所帮助!