同一tomcat下实现多应用session共享 单点登录

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/v2sking/article/details/71937594
随着web开发的应用程序越来越复杂,我们可能会将原有的一个应用拆分成多个应用,同时也应该支持新增加的应用扩展,

但又希望通过单点登录统一管理所有的应用,二每一个web项目的session是独立的,不能只能同一管理,

而现在有很多比较流行的技术实现单点登陆 比如cas单点登录,restful令牌等等。

cookie共享等等,但是结余我们很多应用是很久之前开发的,使用session来管理,未考虑扩展,新的应用想集成进来时不免遇到困难,这里提供一种解决方案
同一tomcat下实现多应用session共享,实现单点登录


通过主应用ContextA实现单点登陆

1.tomcat server.xml 开启crossContext共享
<Host name="localhost"  appBase="webapps"
            unpackWARs="true" autoDeploy="true"
            xmlValidation="false" xmlNamespaceAware="false">
 
        <Context path="/ContextA"  debug="9" reloadable="true" crossContext="true"/> 
        <Context path="/ContextB"  debug="9" reloadable="true" crossContext="true"/>
 
    </Host>



2.主应用ContextA 登录后设置session到ServletContext 

这里设置用户id admin 作为 ServletContext键,并且记录该请求的ip地址, 因此不支持一个账号多处同时登录

	session.setAttribute("user", user);
	session.setAttribute("ipAddr", getIpAddress(request));
	session.getServletContext().setAttribute("session", session);

3.应用ContextB 登录页

@RequestMapping(value = "/login")
	public String login(HttpSession session,HttpServletRequest request) {
		ServletContext ContextB = session.getServletContext();  
        ServletContext ContextA= ContextB.getContext("/ContextA");// 这里面传递的是 ContextA的虚拟路径
        HttpSession sessionA =(HttpSession)ContextA.getAttribute("admin");
        if (sessionA != null) {
        	String ip = sessionA.getAttribute("ipAddr").toString();
        	if (!ip.equals(getIpAddress(request))) {
				logger.error("ip地址校验不通过"); 
				return null;
			}
            try{
                Object attribute = sessionA.getAttribute("user");
                if(attribute!= null){
                    System.out.println("user: "+attribute);
                    session.setAttribute("user", attribute);
                                        //TODO:已经登录跳转到首页
                }
            }catch(IllegalStateException e){
                System.out.println("ContextA session 已经失效");
            }
             
        }
		return "login";
	}




4.通过以上步奏session共享是解决了,但是如果在主应用或子应用中登出,或着session到期,存在ServletContext 中的session是没办法销毁的,导致session失效无法同步,这种情况可以采用HttpSessionListener监听session销毁,同步其他应用的session

设置HttpSessionListener 实现session失效同步 

ContextA:

import javax.servlet.http.HttpSessionListener;  
    import javax.servlet.http.HttpSessionEvent;  
       
public class SessionCounter implements HttpSessionListener {  
    private static int activeSessions =0;  
    /* Session创建事件 */  
    public void sessionCreated(HttpSessionEvent se) {  
          
    }  
    /* Session失效事件 */  
    public void sessionDestroyed(HttpSessionEvent se) {  
     ServletContext ContextA=se.getSession().getServletContext();  
     ServletContext ContextB= ContextA.getContext("/ContextB");
     HttpSession sessionB =(HttpSession)ContextB.getAttribute("admin");
        if (sessionB != null) {
            sessionB.invalidate();
        }   
   
   
    } 
} 



ContextB:

import javax.servlet.http.HttpSessionListener;  
    import javax.servlet.http.HttpSessionEvent;  
       
public class SessionCounter implements HttpSessionListener {  
    private static int activeSessions =0;  
    /* Session创建事件 */  
    public void sessionCreated(HttpSessionEvent se) {  
          
    }  
    /* Session失效事件 */  
         public void sessionDestroyed(HttpSessionEvent se) {  
     ServletContext ContextB=se.getSession().getServletContext();  
     ServletContext ContextA= ContextA.getContext("/ContextA");
     HttpSession sessionA =(HttpSession)ContextA.getAttribute("admin");
        if (sessionA != null) {
            sessionA.invalidate();
        }   
    }
} 


web.xml配置session监听器

<listener>  
    <listener-class>demo.listener.SessionCounter</listener-class>  
</listener> 


扩展:示例是两个应用实现共享,如果有多个应用可以在主登录应用ServletContext维护一个包含所有子应用的context列表,具体操作遍历即可

猜你喜欢

转载自blog.csdn.net/v2sking/article/details/71937594