实现的原理:

  所有子系统的登录全部交由一个登录系统去实现,登录成功后生成一个ticket,并将ticket和用户名作为一个键值对保存在登录系统中,同时将用户名保存在cookie中。然后重定向回到原来的请求路径,子系统会根据ticket请求登录系统获取用户名,成功后,登录系统删掉ticket和用户名,并将用户名保存在session中,当session中有用户名后不会再被过滤重定向到登录系统。

  当一个子系统登录成功后,请求其他子系统时,session中并没有用户名会重定向到登录系统,登录系统会获取cookie中的用户名,获取到用户名后会生成一个ticket,再次将ticket和用户名作为一个键值对保存在登录系统中,并再重定向会原来的请求并携带上ticket,此时就会根据ticket请求登录系统获取用户名,并存入session。

  登出时只需要删除cookie,并在子系统做判断,当session中用户名与cookie中用户名不一致时,则认为没有登录,要求重新登录即可。

 

实现步骤:

  因为需要同时启动3个项目(不同的端口号),一个登录系统,两个子系统,使用tomcat不太方便,这里使用的是jetty插件。

  在pom.xml文件中进行配置,然后使用maven build启动即可。

<plugins>  
      <plugin>  
          <groupId>org.mortbay.jetty</groupId>  
jetty-maven-plugin</artifactId>  
          <version>8.1.9.v20130131</version>  
          <configuration>  
              <stopKey>stop</stopKey>  
              <stopPort>6001</stopPort>   <!--  3个项目的端口号都不相同   -->
              <webAppConfig>  
                  <contextPath>/client1</contextPath>  
              </webAppConfig>  
              <scanIntervalSeconds>4</scanIntervalSeconds>  
              <connectors>  
                  <connector implementation="org.eclipse.jetty.server.nio.SelectChannelConnector">  
                      <port>8082</port>   <!--  3个项目的端口号都不相同   -->
                      <maxIdleTime>60000</maxIdleTime>  
                  </connector>  
              </connectors>  
          </configuration>  
      </plugin>  
</plugins>

 

登录系统:

登录效验:

protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		 	  String username = req.getParameter("username");  
	          String password = req.getParameter("password");  
	          String service = req.getParameter("service");//原来请求的路径  
	          /**
	           * 此处应该访问数据库效验用户
	           * */
	          if ("test".equals(username) && "test".equals(password)) {  
	              Cookie cookie = new Cookie("sso", username);//效验通过,将用户名存入cookie  
	              cookie.setPath("/"); //设置的cookie路径 
	              resp.addCookie(cookie);  //写入客户端
	              long time = System.currentTimeMillis();  
	              String timeString = username + time;  //生成ticket凭证
	              JVMCache.TICKET_AND_NAME.put(timeString, username);  //存入缓存
	              /**
	               * 将ticket返回给原请求地址(登录效验)
	               * */
	              if (null != service) {  
	                  StringBuilder url = new StringBuilder();  
	                  url.append(service);  
	                  if (0 <= service.indexOf("?")) {  
	                      url.append("&");  
	                  } else {  
	                      url.append("?");  
	                  }  
	                  url.append("ticket=").append(timeString);  
	                  resp.sendRedirect(url.toString()); //请求原路径
	              } else {  
	            	  resp.sendRedirect("/ssoServer/index.jsp"); //请求登录页面
	              }  
	          } else {  
	        	  resp.sendRedirect("/ssoServer/index.jsp?service=" + service);  
	          }  
	}过滤所有请求
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		  HttpServletRequest request = (HttpServletRequest) servletRequest;  
          HttpServletResponse response = (HttpServletResponse) servletResponse;  
          String service = request.getParameter("service"); //获取要访问的原地址 
          String ticket = request.getParameter("ticket");  //获取凭证
          //获取cookie中的用户名
          Cookie[] cookies = request.getCookies();  
          String username = "";  
          if (null != cookies) {  
              for (Cookie cookie : cookies) {  
                  if ("sso".equals(cookie.getName())) {  
                        username = cookie.getValue();  
                        break;  
                    }  
               }  
         }  
        //ticket不为空时,为子系统在效验是否登录
        if (null == service && null != ticket) {  
              filterChain.doFilter(servletRequest, servletResponse);  
              return;  
        }  
        /**
         * 用户已经登录
         * */
        if (null != username && !"".equals(username)) {  
              long time = System.currentTimeMillis();  
              String timeString = username + time;  //生成ticket凭证
              JVMCache.TICKET_AND_NAME.put(timeString, username);  //存入缓存
              StringBuilder url = new StringBuilder();
              /**
               * 重新生成token与用户名的缓存,并执行原请求(登录效验)
               * */
              url.append(service);  
              if (0 <= service.indexOf("?")) {  
                    url.append("&");  
              } else {  
                    url.append("?");  
              }  
              url.append("ticket=").append(timeString);  
                response.sendRedirect(url.toString()); //请求原路径并携带上ticket
          } else {  
                filterChain.doFilter(servletRequest, servletResponse);  
          } 
	}返回用户名
protected void doPost(HttpServletRequest req, HttpServletResponse resp) throws ServletException, IOException {
		  /**
		   * 通过效验ticket,返回给子系统用户名
		   * */
		  String ticket = req.getParameter("ticket");  
          String username = JVMCache.TICKET_AND_NAME.get(ticket);  
          JVMCache.TICKET_AND_NAME.remove(ticket);
          //不为空时才返回
          if(null!=username&&!"".equals(username)){
        	    PrintWriter writer = resp.getWriter();  
                writer.write(username);
          }
	} 
子系统:
/**
	 * 过滤所有请求,判断用户是否登录
	 * */
	@Override
	public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain)
			throws IOException, ServletException {
		   HttpServletRequest request = (HttpServletRequest) servletRequest;  
	          HttpServletResponse response = (HttpServletResponse) servletResponse;  
	          HttpSession session = request.getSession();  
	          String username = (String) session.getAttribute("username"); //获取session里的用户名
	          String ticket = request.getParameter("ticket");  //获取ticket
	          String url = URLEncoder.encode(request.getRequestURL().toString(), "UTF-8");  
	          //获取cookies里面的用户名
	          Cookie[] cookies = request.getCookies();  
	          String tempname = "";  
	          if (null != cookies) {  
	                for (Cookie cookie : cookies) {  
	                      if ("sso".equals(cookie.getName())) {  
	                	        tempname = cookie.getValue();  
	                            break;  
	                      }  
	                }  
	          }  
	          //用户名为空说明未登录
	          if (null == username||!tempname.equals(username)) { //cookie和session用户名不一致说明已经登出 
	                if (null != ticket && !"".equals(ticket)) {
	            	    //通过ticket向登录服务器发送请求获取对应用户名
	                    PostMethod postMethod = new PostMethod("http://localhost:8081/ssoServer/ticket");  
	                    postMethod.addParameter("ticket", ticket);  
	                    HttpClient httpClient = new HttpClient();  
	                    try {  
	                          httpClient.executeMethod(postMethod);  
	                          username = postMethod.getResponseBodyAsString();
	                          postMethod.releaseConnection();  
	                    } catch (Exception e) {  
	                          e.printStackTrace();  
	                    }  
	                  //用户名不为空说明已经登录,执行原请求
	                  if (null != username && !"".equals(username)) {  
	                        session.setAttribute("username", username);  
	                        filterChain.doFilter(request, response);  
	                  } else {  //用户名为空,未登录,跳转到登录页面
	                        response.sendRedirect("http://localhost:8081/ssoServer/index.jsp?service=" + url);  
	                  }  
	            } else {  //用户名为空,未登录,跳转到登录页面
	                  response.sendRedirect("http://localhost:8081/ssoServer/index.jsp?service=" + url);  
	            }  
	        } else {  //已登录,执行原请求
	              filterChain.doFilter(request, response);  
	        } 
	}