通过java监听器实现简单的单点登录功能(基于SSH2框架)

          前阵子做了个java web的项目,里面一个单点登录的功能废了一番功夫,所幸后来经过讨论和百度还是做出来了。以下总结梳理一下我的思路:

          1、功能需求:同一用户在不同浏览器或不同IP地址再次登陆时,前一次登陆的用户登陆状态失效,再次做需要登录权限的请求时会跳转到登陆界面。

          2、实现思路:

           2.1 前端通过ajax提交登陆请求,在LoginAction中判断登陆成功的同时将qname和Sessionid放入session的Attribute中

           L oginAciton的部分代码见:              

          
public void loginOk(){
        HttpServletResponse res=ServletActionContext.getResponse();
        PrintWriter out=null;
        String str=null;
        try {
            out=res.getWriter();
        } catch (IOException e) {
            // TODO Auto-generated catch block
            e.printStackTrace();
        }
        
        if(qUserBiz.isLoginOk(qname, qpassword)){
            HttpServletRequest request=ServletActionContext.getRequest();
            session=request.getSession();
            //用户ip地址
            //String uip=request.getRemoteAddr();
            session.setAttribute("qname", qname);//登陆的用户名
            System.out.println("将qname"+qname+"放入Session中");
            String sid=session.getId();//SessionId
            session.setAttribute("sid", sid);
            System.out.println("将sid"+sid+"放入Session中");
            //session.setAttribute("uip",uip);
            //System.out.println("将uip"+uip+"放入Session中");
            str= "success";
            }else{
               str="fail";
            }
            out.write(str);
            out.flush();
            out.close();
     }
     
     public void isLogin(){
		HttpServletResponse res=ServletActionContext.getResponse();
		PrintWriter out=null;
		try {
			out=res.getWriter();
		} catch (IOException e) {
			e.printStackTrace();
		}
		HttpServletRequest request=ServletActionContext.getRequest();
		session=request.getSession();
		System.out.println("LA.session:"+session.getId());
		if(session!=null){
			String qname=(String) session.getAttribute("qname");
			System.out.println("LA.qname:"+qname);
			if(qname!=null){
				out.write(qname);
				
			}else{
				out.write("");
				
			}
		}
		out.flush();
		out.close();
	}

           2.2创建LoginListener监听器实现 HttpSessionListener,HttpSessionAttributeListener接口,监听登陆时的每次Session.setAttribute操作。将qname和Sessionid存放入相应的Map中,两个Map用相同的变量i做Key以保证qname和Session的一一对应关系。当已登录即UsersMap中已存在的qname登陆时,通过其相同的i去找SessMap中对应的sessionid,并通过该id销毁之前连接的Session。将新的Sessionid存入到SessMap中。

          LoginListener的代码如下:

         
package com.etc.listener;

import java.util.HashMap;
import java.util.Map;
import java.util.Set;

import javax.servlet.http.HttpSession;
import javax.servlet.http.HttpSessionAttributeListener;
import javax.servlet.http.HttpSessionBindingEvent;
import javax.servlet.http.HttpSessionEvent;
import javax.servlet.http.HttpSessionListener;

import com.etc.util.MySessionContext;
/**
 * 实现单点登录的监听器
 * @author tl
 *
 */
public class LoginListener implements HttpSessionListener,HttpSessionAttributeListener{
	 private   MySessionContext myc=MySessionContext.getInstance();  
	// private static Map loginUsers = new HashMap();
	 //1、声明两个Map分别用来存放用户名和sessionid,通过相同的i变量为key保持同一用户的用户名和连接的sessionid一一对应
	 private static Map Users=new HashMap();
	 //key为i Value为qname
	 private static Map Sesss=new HashMap();
	 //key为i Value为sid
	 private static int flag=0;
	 
	public void attributeAdded(HttpSessionBindingEvent arg0) {
		//2、监听attribute的添加事件,拿到添加的属性qname和sid的值
		String qname=(String)arg0.getSession().getAttribute("qname");
		System.out.println("ADDqname:"+qname);
		String sid=(String)arg0.getSession().getAttribute("sid");
		System.out.println("ADDsid:"+sid);
		//根据ip地址的不同实现单点登录
		/*String uip=(String)arg0.getSession().getAttribute("uip");
		System.out.println("ADDuip:"+uip);*/
		//根据SessionID的不同实现单点登录
		//long random=System.currentTimeMillis();
		//String i=random+"";
		String i=flag+"";
		System.out.println("i"+i);
		if(qname!=null&&sid!=null){
			String j=null;
			//3、判断qname是否存在于Users的Map中,取出其对应的key去找Sess的Map中对应的Sessionid
			System.out.println("qname:"+qname+"是否存在在Users中");
			System.out.println(Users.containsValue(qname));
			if(Users.containsValue(qname)){
				for(Map.Entry entry:Users.entrySet()){
				    if(qname.equals(entry.getValue())){
				    		j=(String) entry.getKey();
				    		System.out.println("users中qname对应的i"+j);
				    }
				    String sids=(String)Sesss.get(j);
				    System.out.println(j+"在Sesss中对应的sessid"+sids);
				    //4、将该Sessionid对应的session销毁,断开连接
				    MySessionContext myc= MySessionContext.getInstance();  
					   HttpSession sess = myc.getSession(sids); 
					   sess.removeAttribute("qname");
					   sess.invalidate();
					   flag=flag-1;
					   String w=flag+"";
					   Sesss.put(w,sid); 
			  }
			} else {
				//当qname不存在于map中时将qname及其对应的sessionid已相同的key分别存放在对应的Map中
				Users.put(i, qname);
				Sesss.put(i, sid);
				flag++;
				
			}
			Set key = Users.keySet();
			for (String k : key) {
				System.out.println("Users中i:" + k + " qname:"
						+ Users.get(k));
			}
			Set key1 = Sesss.keySet();
			for (String k1 : key1) {
				System.out.println("Sesss中i:" + k1 + " sid:"
						+ Sesss.get(k1));
			}
		}
	}

	public void attributeRemoved(HttpSessionBindingEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public void attributeReplaced(HttpSessionBindingEvent arg0) {
		// TODO Auto-generated method stub
		
	}

	public void sessionCreated(HttpSessionEvent se) { 
	   myc.AddSession(se.getSession());  
	}

	public void sessionDestroyed(HttpSessionEvent se) {
		// TODO Auto-generated method stub
		HttpSession session = se.getSession();  
		System.out.println("sessionId"+session.getId()+"正在被销毁");
		myc.DelSession(session);  
	}

}

         另,由于没有SessionContext方法,故百度后发现要写一个MySessionContext类才能通过Sessionid找到对应的Session实现销毁。MySessionContext类见下:
        
        
package com.etc.util;

import javax.servlet.http.HttpSession;
import java.util.HashMap;

public class MySessionContext {
	private static MySessionContext instance;
	private HashMap mymap;

	private MySessionContext() {
		mymap = new HashMap();
	}

	public static MySessionContext getInstance() {
		if (instance == null) {
			instance = new MySessionContext();
		}
		return instance;
	}

	public synchronized void AddSession(HttpSession session) {
		if (session != null) {
			mymap.put(session.getId(), session);
		}
	}

	public synchronized void DelSession(HttpSession session) {
		if (session != null) {
			mymap.remove(session.getId());
		}
	}

	public synchronized HttpSession getSession(String session_id) {
		if (session_id == null)
			return null;
		return (HttpSession) mymap.get(session_id);
	}

}

           2.3在需要登录才能访问的页面中加入islogin方法,通过调用LoginAction中的isLogin()方法来显示登陆状态或者跳转到注册页面。

function islogin(){
$.post(
"islogin.action",
{},
function(obj){
if(obj!=""){
$("#islogin").html(obj+" 已登录");
}else{
location.href="/ZSWS/account.html";
}
},
"text"
);
}   

           至此,基于监听器实现的java web项目的单点登录就实现了,一开始也有想过用一个Map,key存放qname,value存放sessionid,但是由于Map是不可重复的,只会保留最后的Sessionid,而无法得到一开始连接的Sessionid也就无法通过它销毁之前的Session故写了两个Map用相同的Key将他们一一对应起来,在更改Sessionid之前先取出一开始的Sessionid关掉之前的连接即可。另此处是为了在不同浏览器之间实现单点登录,故存放的是Sessionid如果要实现不同ip的单点存放Sessionip即可。如果有不对的地方欢迎指正。

————————————————————————————聚沙成塔,滴水石穿。


          

你可能感兴趣的:(my,code)