最近公司要做一个单点登陆的应用,整合论坛和网站。到网上找了好些资料,终于圆满解决,博客中记录一下一面忘掉。
单点登录首先首先要保持数据库数据的一致性,这个实现方式很多我就不多废话了。
刚开始我的想法是在一个应用中登陆的时候发送一个http请求到另一个应用保证两个应用同时拥有session,后来考虑到session过期不同步的问题只能放弃。为了保持session的完全同步我只能求助于cookie,首先说一下思路: 1.为了两个应用个应用能同时访问到cookie,cookie设置的时候要设置path在根目录(同一个服务器下的不 同应用,不在同一个应用下可以用共用域名比如说 .baidu.com),必须保证cookie在统一一个域下 2.在访问一个应用的时候首先检测session如果存在就是已经登录保存cookie(保证cookie是最新的) 3.如果session不存在检测cookie如果cooki不存在说明在另一应用中也没有登录 4.cookie存在检测创建时间(当然保存的时候要设置一个时间)如果没有过期就用cookie中保存的用户名密码调用一下登录方法 5.登陆成功保存cookie
为了保证每次请求都能检测我使用了filter下面贴一下filter代码 import java.io.IOException;
import javax.servlet.Filter; import javax.servlet.FilterChain; import javax.servlet.FilterConfig; import javax.servlet.ServletException; import javax.servlet.ServletRequest; import javax.servlet.ServletResponse; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public class LoginFilter implements Filter {
private String loginInfoPath; public void destroy() { loginInfoPath = null; }
public void doFilter(ServletRequest sreq, ServletResponse sresp, FilterChain chain) throws IOException, ServletException { HttpServletRequest req = (HttpServletRequest) sreq; HttpServletResponse resp = (HttpServletResponse) sresp; Class loginInfoClass = null; LoginInfoBase loginInfo = null; try { loginInfoClass = Class.forName(loginInfoPath); loginInfo = (LoginInfoBase) loginInfoClass.newInstance(); } catch (ClassNotFoundException e) { e.printStackTrace(); } catch (InstantiationException e) { e.printStackTrace(); } catch (IllegalAccessException e) { e.printStackTrace(); } loginInfo.setReq(req); loginInfo.setResp(resp); //session值为空 if(loginInfo.isSessionEmpty()){ if(loginInfo.init()){ boolean loginResult = loginInfo.doLogin(); if(loginResult){ loginInfo.saveCookie(); } } }else{ if(loginInfo.init()){ //另外一套系统已经退出 if("out".equals(loginInfo.getLoginState())){ loginInfo.doLogout(); CookieUtil.delCookie(resp, LoginInfoBase.COOKIE_NAME); } } } chain.doFilter(sreq, sresp); }
public void init(FilterConfig config) throws ServletException { this.loginInfoPath = config.getInitParameter("loginInfoPath"); }
public String getLoginInfoPath() { return loginInfoPath; }
public void setLoginInfoPath(String loginInfoPath) { this.loginInfoPath = loginInfoPath; }
} loginInfoPath 在web.xml中配置指明LoginInfoBase的子类的完整路径用来反射
LoginInfoBase代码: package com.yt.util;
import java.text.SimpleDateFormat; import java.util.Date;
import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public abstract class LoginInfoBase { public static final String SEPARATION = "-->"; public static final String DATE_FORMAT = "yyyy-MM-dd HH:mm:ss"; public static final long COOKIE_TIME = 1800000; public static final String COOKIE_NAME = "loginInfo"; public static final String COOKIE_PATH = "/";
protected HttpServletRequest req; protected HttpServletResponse resp;
protected Date sessionTime; protected String userName; protected String userPass; protected String loginState;
public LoginInfoBase() { super(); }
public LoginInfoBase(HttpServletRequest req, HttpServletResponse resp) { super(); this.req = req; this.resp = resp; }
public LoginInfoBase(String userName, String pwd, Date sessionTime) { this.userName = userName; this.userPass = pwd; this.sessionTime = sessionTime; }
abstract void doLogout(); abstract boolean isSessionEmpty(); abstract boolean doLogin();
public HttpServletRequest getReq() { return req; } public void setReq(HttpServletRequest req) { this.req = req; } public HttpServletResponse getResp() { return resp; } public void setResp(HttpServletResponse resp) { this.resp = resp; }
//初始化登录对象 protected boolean init(){ String loginInfoStr = CookieUtil.getValue(req, LoginInfoBase.COOKIE_NAME); if(loginInfoStr == null || "".equals(loginInfoStr)){ return false; } String[] infoArray = loginInfoStr.split(SEPARATION); if(infoArray.length>3){ this.userName = DigestUtil.getFromBASE64(infoArray[0]); this.userPass = DigestUtil.getFromBASE64(infoArray[1]); this.sessionTime = buildDate(infoArray[2]); this.loginState = infoArray[3]; } if(new Date().getTime() - getSessionTime().getTime() > LoginInfo.COOKIE_TIME){ CookieUtil.delCookie(resp, LoginInfo.COOKIE_NAME); return false; } return true; }
protected void saveCookie(){ setSessionTime(new Date()); setLoginState("in"); CookieUtil.addCookie(resp, LoginInfo.COOKIE_NAME, toString(), "/"); }
public void clearCookie(){ setUserName("XX"); setUserPass("XX"); setSessionTime(new Date()); setLoginState("out"); CookieUtil.addCookie(resp, LoginInfo.COOKIE_NAME, toString(), "/"); }
@Override public String toString() { return DigestUtil.getBASE64(userName)+SEPARATION+DigestUtil.getBASE64(userPass)+SEPARATION+formateSessionTime()+SEPARATION+loginState; }
private String formateSessionTime(){ SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); String timeStr =df.format(sessionTime); return timeStr; } private Date buildDate(String sessionTime) { SimpleDateFormat df = new SimpleDateFormat(DATE_FORMAT); Date date = null; try { date = df.parse(sessionTime); }catch (Exception ex){ System.out.println(ex.getMessage()); } return date; }
public Date getSessionTime() { return sessionTime; }
public void setSessionTime(Date sessionTime) { this.sessionTime = sessionTime; }
public String getUserName() { return userName; }
public void setUserName(String userName) { this.userName = userName; }
public String getUserPass() { return userPass; }
public void setUserPass(String userPass) { this.userPass = userPass; }
public String getLoginState() { return loginState; }
public void setLoginState(String loginState) { this.loginState = loginState; }
} doLogin(),doLogout(),isSessionEmpty()必须在子类中实现实现 分别用来登录系统,注销系统,判断是否登录
ok,比较乱不懂的可以提问
有人要求Util的代码,无语,贴出来吧
package net.heart.util;
import java.io.UnsupportedEncodingException; import java.net.URLDecoder; import java.net.URLEncoder;
import javax.servlet.http.Cookie; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse;
public abstract class CookieUtil {
public static void addCookie(HttpServletResponse response,String name,String value,int maxAge){ try { Cookie cookie=new Cookie(name,URLEncoder.encode(value, "utf-8")); cookie.setMaxAge(maxAge); response.addCookie(cookie); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } } public static String getValue(HttpServletRequest request,String name){ String value=null; Cookie[] cookies=request.getCookies(); if(cookies!=null){ for(Cookie cookie:cookies){ if(name.equals(cookie.getName())){ try { value=URLDecoder.decode(cookie.getValue(),"utf-8"); } catch (UnsupportedEncodingException e) { // TODO Auto-generated catch block e.printStackTrace(); } break; } } } return value; } public static void delCookie(HttpServletResponse response,String name){ Cookie cookie=new Cookie(name,""); cookie.setMaxAge(0); response.addCookie(cookie); } }
|