主要参考文档:
1、工程总体结构:
2、修改C:\Windows\System32\drivers\etc\hosts文件,加入以下一段配置:
127.0.0.1 wangyu.prc.sun.com
这样可以保证3个web应用处于同一个域中(和cookie访问有关),并且不用修改作者提供的示例代码。
3、首先看SSOWebDemo1这个应用第一次访问时,
SSOFilter sso.SSOFilter SSOFilter /*
其中SSOFilter的doFilter方法如下:
/** * * @param request The servlet request we are processing * @param result The servlet response we are creating * @param chain The filter chain we are processing * * @exception IOException if an input/output error occurs * @exception ServletException if a servlet error occurs */ public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException { if (debug) log("SSOFilter:doFilter()"); HttpServletRequest request = (HttpServletRequest) req; HttpServletResponse response = (HttpServletResponse) res; String result="failed"; String url = request.getRequestURL().toString(); String qstring = request.getQueryString(); if (qstring == null) qstring =""; String cookieValue =""; javax.servlet.http.Cookie[] diskCookies = request.getCookies(); if (diskCookies != null) { for (int i = 0; i < diskCookies.length; i++) { if(diskCookies[i].getName().equals(cookieName)){ cookieValue = diskCookies[i].getValue(); //如果携带有cookie信息,则判断该cookie是否有效(即已经成功通过SSO单点认证服务器) result = SSOService(cookieValue); if (debug) log("found cookies!"); } } } if (result.equals("failed")) { //如果没有携带cookie信息或者cookie验证失效,则需要重新登录SSO验证服务器 response.sendRedirect(SSOLoginPage+"?goto="+url); } else if (qstring.indexOf("logout") > 1) { if (debug) log("logout action!"); logoutService(cookieValue); response.sendRedirect(SSOLoginPage+"?goto="+url); } else { request.setAttribute("SSOUser",result); Throwable problem = null; try { chain.doFilter(req, res); } catch(Throwable t) { problem = t; t.printStackTrace(); } if (problem != null) { if (problem instanceof ServletException) throw (ServletException)problem; if (problem instanceof IOException) throw (IOException)problem; sendProcessingError(problem, res); } } }
其中SSOLoginPage 为"http://wangyu.prc.sun.com:8080/SSOAuth/login.jsp",在首次访问这个web应用时会请求这个URI进行SSO登陆验证,否则会调用SSOService方法验证该客户端是否已经通过验证(通过携带的cookie),SSOService方法如下:
private String SSOService(String cookievalue) throws IOException { String authAction = "?action=authcookie&cookiename="; HttpClient httpclient = new HttpClient(); GetMethod httpget = new GetMethod(SSOServiceURL+authAction+cookievalue); try { httpclient.executeMethod(httpget); String result = httpget.getResponseBodyAsString(); return result; } finally { httpget.releaseConnection(); } }
其中SSOServiceURL为"http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuth",所以这个方法会请求URI:
http://wangyu.prc.sun.com:8080/SSOAuth/SSOAuth?action=authcookie&cookiename=xxx验证该客户端是否有效。
如果客户端携带的cookie有效则通过该Filter,继续处理该请求。
4、这里的SSO验证使用的是一个Servlet,主要的功能是验证初始的用户名密码是否合法、产生cookie发送到客户端、以及验证客户端的cookie是否有效。
4.1、定义的成员变量
//保存用户信息(对应的用户名和密码) static private ConcurrentMapaccounts; //保存已经登录的用户信息(对应的cookie信息和用户名) static private ConcurrentMap SSOIDs;
ConcurrentMap为线程安全的集合类。
4.2、假设以下的四个用户为合法用户
public void init(ServletConfig config) throws ServletException { super.init(config); SSOIDs = new ConcurrentHashMap(); accounts = new ConcurrentHashMap (); accounts.put("admin", "admin"); accounts.put("wangyu", "wangyu"); accounts.put("paul", "paul"); accounts.put("carol", "carol"); }
4.3、处理该客户端第一次登陆的代码
private void handlerFromLogin(HttpServletRequest request, HttpServletResponse response) throws ServletException, IOException { String username = request.getParameter("username"); String password = request.getParameter("password"); String pass = (String) accounts.get(username); if ((pass == null) || (!pass.equals(password))) getServletContext().getRequestDispatcher("/failed.html").forward( request, response); else { String gotoURL = request.getParameter("goto"); String newID = createUID(); SSOIDs.put(newID, username); //登录的用户名和密码合法,往客户端写入一个cookie,值为自定义生成的id(一段字符串加上当前时间) Cookie wangyu = new Cookie(cookiename, "22222"); wangyu.setDomain(".sun.com"); // 60分钟之内cookie有效 wangyu.setMaxAge(60 * 60); wangyu.setValue(newID); wangyu.setPath("/"); response.addCookie(wangyu); System.out.println("login success, goto back url:" + gotoURL); if (gotoURL != null) { PrintWriter out = response.getWriter(); response.sendRedirect(gotoURL); out.close(); } } }
4.4、根据客户端传递过来的cookie的值,来判断该cookie是否合法(已登录并有效)
/* * authentication from cookie, If exists and hold in MAP, return the user * name as content else return "failed" */ /* * protected String authCookie(HttpServletRequest request){ Cookie[] * diskCookies = request.getCookies(); if (diskCookies == null) return * "failed"; for (Cookie cookie : diskCookies){ * if(cookie.getName().equals(cookiename)){ String sessionContent = (String) * SSOIDs.get(cookie.getValue()); if (sessionContent == null) return * "failed"; else return sessionContent; } * * } return "failed"; } */ // static method used by other servlet in the same container static public String authCookie(String value) { String result = (String) SSOIDs.get(value); if (result == null) result = "failed"; return result; }
5、SSOWebDemo2的处理逻辑同SSOWebDemo1,也是一个SSOFilter控制单点登陆以及cookie的验证。因为SSOWebDemo1和SSOWebDemo2处在一个cookie的域中,所以SSO验证服务器为SSOWebDemo1产生的cookie,在SSOWebDemo2访问验证服务器时也会携带。
6、运行效果
6.1、环境tomcat6
6.2、访问SSOWebDemo1并登陆
6.3、访问SSOWebDemo2,这次不需要登陆
7、整理代码zip