单点登陆简单实现(完全跨域、单点退出)

单点登陆活动图

废话不多说直接上代码咯,什么好处,实现原理相关资料baidu去,基本都一样,就不复制了

1.验证中心核心代码

(1)登陆跳转注销代码   controller层代码

[java] view plain copy
 
  1. package com.ffcs.sso.controller;  
  2.   
  3. import javax.servlet.http.HttpSession;  
  4.   
  5. import org.apache.commons.lang.StringUtils;  
  6. import org.slf4j.Logger;  
  7. import org.slf4j.LoggerFactory;  
  8. import org.springframework.beans.factory.annotation.Autowired;  
  9. import org.springframework.stereotype.Controller;  
  10. import org.springframework.ui.Model;  
  11. import org.springframework.web.bind.annotation.RequestMapping;  
  12. import org.springframework.web.bind.annotation.RequestMethod;  
  13. import org.springframework.web.bind.annotation.RequestParam;  
  14. import org.springframework.web.servlet.ModelAndView;  
  15.   
  16. import com.ffcs.sso.pojo.User;  
  17. import com.ffcs.sso.service.LogoutManagerService;  
  18. import com.ffcs.sso.service.TicketManagerService;  
  19. import com.ffcs.sso.service.UserManagerService;  
  20. import com.ffcs.sso.utils.Constant;  
  21. /** 
  22.  *  
  23.  * @author damon 
  24.  * 
  25.  */  
  26. @Controller  
  27. public class SSOController {  
  28.       
  29.     private final static Logger LOGGER=LoggerFactory.getLogger(SSOController.class);  
  30.    
  31.     @Autowired  
  32.     private TicketManagerService ticketManagerService;  
  33.       
  34.     @Autowired  
  35.     private UserManagerService userManagerService;  
  36.       
  37.     @Autowired  
  38.     private LogoutManagerService logoutManagerService;  
  39.   
  40.     /** 
  41.      * 主页 
  42.      * @return 
  43.      */  
  44.     @RequestMapping(value="manager/index",method=RequestMethod.GET)  
  45.     public String index(){  
  46.           
  47.         return "index";  
  48.     }  
  49.     /** 
  50.      * 登陆首页 
  51.      * @return 
  52.      */  
  53.     @RequestMapping(value="login",method=RequestMethod.GET)  
  54.     public ModelAndView loginIndex(String queryParams,String targetUrl,ModelAndView modelAndView){  
  55.           
  56.         modelAndView.addObject("queryParams", queryParams);  
  57.           
  58.         modelAndView.addObject("targetUrl", targetUrl);  
  59.           
  60.         modelAndView.setViewName("login");  
  61.           
  62.         return modelAndView;  
  63.     }  
  64.       
  65.     @RequestMapping(value="login",method=RequestMethod.POST)  
  66.     public String login(@RequestParam(required = true) String account, @RequestParam(required = true) String password,  
  67.   
  68.             String targetUrl, String queryParams, Model model, HttpSession session) {  
  69.   
  70.         User user = userManagerService.getUserInfo(account, password);  
  71.   
  72.         if (user != null) {  
  73.   
  74.             String homeCookieId = session.getId();  
  75.   
  76.             session.setAttribute(Constant.SSO_IS_LOGIN, true);  
  77.   
  78.             session.setAttribute(Constant.SSO_LOGIG_INFO, account);  
  79.   
  80.             logoutManagerService.saveLoginUserInfo(homeCookieId, user);  
  81.   
  82.             if (StringUtils.isNotBlank(targetUrl)) {  
  83.   
  84.                 // 生成targetURL对应的票  
  85.   
  86.                 String ticket = ticketManagerService.generateTicket(targetUrl, homeCookieId);  
  87.   
  88.                 String params = StringUtils.isNotBlank(queryParams) ? "&" + queryParams : "";  
  89.   
  90.                 LOGGER.info("###################  用户账号:[{}]  对应主站cookieId:[{}] 登陆系统 :[{}]", account, homeCookieId, targetUrl);  
  91.   
  92.                 return "redirect:" + targetUrl + "?" + Constant.SSO_TICKET + "=" + ticket + params;  
  93.   
  94.             }  
  95.             return "redirect:manager/index";  
  96.   
  97.         } else {  
  98.   
  99.             model.addAttribute("error", "用户名或密码错误!");  
  100.   
  101.             if (StringUtils.isNotBlank(targetUrl)) {  
  102.   
  103.                 model.addAttribute("targetUrl", targetUrl);  
  104.             }  
  105.             return "login";  
  106.         }  
  107.     }  
  108.       
  109.     /** 
  110.      * 重定向到子系统并生成票 
  111.      * @param targetUrl 
  112.      * @param queryParams 
  113.      * @param modelAndView 
  114.      * @param session 
  115.      * @return 
  116.      */  
  117.     @RequestMapping(value="redirect",method=RequestMethod.GET)  
  118.     public ModelAndView redirect(@RequestParam(value="targetUrl",required=true)String targetUrl,  
  119.               
  120.             String queryParams,ModelAndView modelAndView,HttpSession session) {  
  121.       
  122.         if(session.getAttribute(Constant.SSO_IS_LOGIN)==null){  
  123.               
  124.             modelAndView.setViewName("redirect:login");  
  125.               
  126.             modelAndView.addObject("targetUrl", targetUrl);  
  127.               
  128.             modelAndView.addObject("queryParams", queryParams);       
  129.           
  130.             //重定向到login方法,带上目标网页地址  
  131.           
  132.         }else{  
  133.               
  134.             String homeCookieId=session.getId();  
  135.               
  136.             String account=(String) session.getAttribute(Constant.SSO_LOGIG_INFO);  
  137.               
  138.             //生成targetURL对应的票  
  139.               
  140.             String ticket=ticketManagerService.generateTicket(targetUrl,homeCookieId);  
  141.                       
  142.             String params=StringUtils.isNotBlank(queryParams)?"&"+queryParams:"";  
  143.               
  144.             modelAndView.setViewName("redirect:" + targetUrl + "?" + Constant.SSO_TICKET + "=" + ticket + params);    
  145.   
  146.             LOGGER.info("############### 用户账号:[{}] 主站cookieId:[{}] 重定向到系统:[{}] 对应ticket:[{}]", account, homeCookieId, targetUrl, ticket);  
  147.         }  
  148.           
  149.         return modelAndView;  
  150.     }  
  151.       
  152.     /** 
  153.      * 单点注销 
  154.      * @param session 
  155.      * @return 
  156.      */  
  157.     @RequestMapping(value="logout",method=RequestMethod.GET)  
  158.     public String logout(HttpSession session){  
  159.           
  160.         if(session.getAttribute(Constant.SSO_IS_LOGIN)!=null){  
  161.           
  162.             String cookieId=session.getId();  
  163.               
  164.             String account=(String) session.getAttribute(Constant.SSO_LOGIG_INFO);  
  165.               
  166.             logoutManagerService.logout(cookieId);  
  167.               
  168.             session.invalidate();     
  169.                   
  170.             LOGGER.info("########### 单点退出用户账号:[{}] 对应主站cookieId为:[{}] ",account,cookieId);  
  171.         }  
  172.         return "redirect:login";  
  173.     }     
  174.       
  175. }  

(2)生成票管理接口代码(对外restful webservice发布)

[java] view plain copy
 
  1. package com.ffcs.sso.service;  
  2.   
  3. import java.util.UUID;  
  4.   
  5. import net.rubyeye.xmemcached.MemcachedClient;  
  6.   
  7. import org.apache.commons.lang.StringUtils;  
  8. import org.springframework.beans.factory.annotation.Autowired;  
  9. import org.springframework.beans.factory.annotation.Qualifier;  
  10. import org.springframework.stereotype.Service;  
  11.   
  12. import com.ffcs.sso.exception.SSOException;  
  13. import com.ffcs.sso.pojo.TicketInfo;  
  14. import com.ffcs.sso.pojo.TicketResponseInfo;  
  15. import com.ffcs.sso.pojo.User;  
  16. import com.ffcs.sso.utils.Constant;  
  17. /** 
  18.  *  
  19.  * 票管理 
  20.  *  
  21.  *  
  22.  *  damon 
  23.  * 
  24.  */  
  25. @Service  
  26. public class TicketManagerServiceImpl implements TicketManagerService{    
  27.       
  28.     @Autowired  
  29.     @Qualifier(value="memcachedSSOClient")  
  30.     private MemcachedClient memcachedClient;  
  31.     @Autowired  
  32.     private LogoutManagerService logoutManagerService;  
  33.   
  34.     @Override  
  35.     public String generateTicket(String target,String homeCookieId){  
  36.           
  37.         if(StringUtils.isBlank(target)){  
  38.               
  39.             throw new IllegalArgumentException("target不可以为空!");  
  40.               
  41.         }  
  42.           
  43.         if(StringUtils.isBlank(homeCookieId)){  
  44.               
  45.             throw new IllegalArgumentException("homeCookieId不可以为空!");  
  46.               
  47.         }  
  48.           
  49.         String ticket=UUID.randomUUID().toString();  
  50.       
  51.         try {  
  52.               
  53.             memcachedClient.set(ticket, Constant.MAX_TICKET_INACTIVE_INTERVAL, new TicketInfo(ticket,target,homeCookieId));  
  54.               
  55.             return ticket;  
  56.               
  57.         } catch (Exception e) {  
  58.   
  59.             throw new SSOException(e);  
  60.         }  
  61.     }  
  62.     @Override   
  63.     public TicketResponseInfo validateTicket(String ticket,String target,  
  64.               
  65.             String subCookieId,String subCookieName,String subLogoutPath){  
  66.           
  67.         if(StringUtils.isBlank(ticket)){  
  68.   
  69.             throw new IllegalArgumentException("ticket不可以为空!");  
  70.         }  
  71.           
  72.         if(StringUtils.isBlank(target)){  
  73.   
  74.             throw new IllegalArgumentException("target不可以为空!");  
  75.         }  
  76.           
  77.         if(StringUtils.isBlank(subCookieId)){  
  78.   
  79.             throw new IllegalArgumentException("subCookieId不可以为空!");  
  80.         }  
  81.   
  82.         if(StringUtils.isBlank(subCookieName)){  
  83.   
  84.             throw new IllegalArgumentException("subCookieName不可以为空!");  
  85.         }  
  86.           
  87.         if(StringUtils.isBlank(subLogoutPath)){  
  88.   
  89.             throw new IllegalArgumentException("subLogoutPath不可以为空!");  
  90.         }  
  91.   
  92.         try {  
  93.               
  94.             TicketInfo ticketInfo = memcachedClient.get(ticket);  
  95.               
  96.             if(ticketInfo==null||!target.equals(ticketInfo.getTargetUrl())){  
  97.                   
  98.                 //返回空验证不通过  
  99.                   
  100.                 return new TicketResponseInfo(false);  
  101.             }  
  102.               
  103.             //删除票保存的临时信息  
  104.               
  105.             memcachedClient.delete(ticket);  
  106.               
  107.             String homeCookieId=ticketInfo.getHomeCookieId();  
  108.               
  109.             //验证后保存登出信息(原本验证和登出信息分开提交,一并提交减少访问次数)  
  110.               
  111.             logoutManagerService.saveSubWebsiteLogouInfo(homeCookieId, subLogoutPath, subCookieId, subCookieName);  
  112.                
  113.             User user= logoutManagerService.getLoginUserInfo(homeCookieId);  
  114.               
  115.             return new TicketResponseInfo(true,user.getAccount(),homeCookieId);  
  116.   
  117.         } catch (Exception e) {  
  118.               
  119.             throw new SSOException(e);  
  120.         }   
  121.       
  122.     }  
  123.   
  124.   
  125. }  

(3)单点退出接口(对外restful webservice发布

[java] view plain copy
 
  1. package com.ffcs.sso.service;  
  2.   
  3. import java.util.Set;  
  4.   
  5. import net.rubyeye.xmemcached.MemcachedClient;  
  6.   
  7. import org.apache.commons.lang.StringUtils;  
  8. import org.apache.http.HttpResponse;  
  9. import org.apache.http.client.HttpClient;  
  10. import org.apache.http.client.methods.HttpPost;  
  11. import org.slf4j.Logger;  
  12. import org.slf4j.LoggerFactory;  
  13. import org.springframework.beans.factory.annotation.Autowired;  
  14. import org.springframework.beans.factory.annotation.Qualifier;  
  15. import org.springframework.stereotype.Service;  
  16.   
  17. import com.ffcs.sso.exception.SSOException;  
  18. import com.ffcs.sso.pojo.ActivationInfo;  
  19. import com.ffcs.sso.pojo.LogoutInfo;  
  20. import com.ffcs.sso.pojo.User;  
  21. import com.ffcs.sso.utils.Constant;  
  22.   
  23. /** 
  24.  * 单点退出 
  25.  *  
  26.  * damon 
  27.  */  
  28.   
  29.   
  30. @Service  
  31. public class LogoutManagerServiceImpl implements LogoutManagerService {  
  32.       
  33.     private static final Logger LOGGER=LoggerFactory.getLogger(LogoutManagerServiceImpl.class);  
  34.       
  35.     private final String LOGOUT_PREFIX="LOGOUT_";  
  36.   
  37.     @Autowired  
  38.     @Qualifier("memcachedSSOClient")  
  39.     private MemcachedClient memcachedClient;  
  40.       
  41.     @Autowired  
  42.     private HttpClient httpClient;  
  43.   
  44.     @Override  
  45.     public boolean saveSubWebsiteLogouInfo(String homeCookieId, String logoutPath,String subCookieId,String subCookieName) {  
  46.           
  47.         if(StringUtils.isBlank(homeCookieId)){  
  48.               
  49.             throw new IllegalArgumentException("homeCookieId 不可以为空!");  
  50.         }  
  51.         if(StringUtils.isBlank(logoutPath)){  
  52.           
  53.             throw new IllegalArgumentException("logoutPath 不可以为空!");  
  54.         }  
  55.         if(StringUtils.isBlank(subCookieId)){  
  56.               
  57.             throw new IllegalArgumentException("subWebSite 不可以为空!");  
  58.         }  
  59.         ActivationInfo info=null;  
  60.           
  61.         Set<LogoutInfo> logoutInfos=null;  
  62.           
  63.         try {  
  64.               
  65.             info=memcachedClient.get(LOGOUT_PREFIX + homeCookieId);  
  66.               
  67.             if(info==null){  
  68.                   
  69.                 info=new ActivationInfo();  
  70.       
  71.             }  
  72.             logoutInfos=info.getLogoutInfo();  
  73.               
  74.             logoutInfos.add(new LogoutInfo(logoutPath,subCookieId,subCookieName));  
  75.               
  76.             info.setLogoutInfo(logoutInfos);  
  77.               
  78.             memcachedClient.set(LOGOUT_PREFIX + homeCookieId, Constant.MAX_USERINFO_INACTIVE_INTERVAL, info);  
  79.                   
  80.             LOGGER.debug("############### 保存子站登出信息 ,子站登出地址 url:{}, 子站cookie:{}, 主站cookie:{}", logoutPath, subCookieId, homeCookieId);  
  81.               
  82.             return true;  
  83.           
  84.         } catch (Exception e) {  
  85.               
  86.             throw new SSOException(e);  
  87.         }   
  88.   
  89.     }  
  90.   
  91.     @Override  
  92.     public void logout(String homeCookieId) {  
  93.           
  94.         if(StringUtils.isBlank(homeCookieId)){  
  95.               
  96.             throw new IllegalArgumentException("cookieId 不可以为空!");  
  97.         }  
  98.            
  99.         ActivationInfo info=null;  
  100.           
  101.         Set<LogoutInfo> logoutInfos=null;  
  102.           
  103.         try {  
  104.               
  105.             info = memcachedClient.get(LOGOUT_PREFIX+homeCookieId);  
  106.               
  107.             memcachedClient.delete(LOGOUT_PREFIX+homeCookieId);  
  108.               
  109.             if(info==null|| (logoutInfos=info.getLogoutInfo())==null){  
  110.                   
  111.                 LOGGER.debug("##############  用户 cookieId:[{}] 未登陆任何系统   !",homeCookieId);  
  112.   
  113.                 return;  
  114.             }     
  115.         } catch (Exception e) {  
  116.               
  117.             LOGGER.error("###############   Memcached获取单点登出信息失败", e);  
  118.               
  119.             return;  
  120.         }   
  121.           
  122.         for (LogoutInfo logoutInfo:logoutInfos) {  
  123.   
  124.             HttpPost post=null;  
  125.               
  126.             try {  
  127.   
  128.                 post = new HttpPost(logoutInfo.getLogoutPath());  
  129.                   
  130.                 post.setHeader("charset", "UTF-8");  
  131.                   
  132.                 post.setHeader("Connection", "close");    
  133.                   
  134.                 //添加cookie模拟回调时候子系统能找到session  
  135.                   
  136.                 post.setHeader("Cookie",logoutInfo.getSubCookieName()+"="+logoutInfo.getSubCookieId());  
  137.   
  138.                 HttpResponse response = httpClient.execute(post);  
  139.   
  140.                 LOGGER.debug("########## 登出子站  :[{}] 主站cookie:[{}] 子站cookie:[{}]  登出返回状态码:[{}]  ",  
  141.                           
  142.                         logoutInfo.getLogoutPath(), homeCookieId, logoutInfo.getSubCookieId(),  response.getStatusLine().getStatusCode());  
  143.                   
  144.             } catch (Exception e) {  
  145.                   
  146.                 LOGGER.error("########## 注销子系统失败,子系统信息:{}",logoutInfo.toString(),e);  
  147.               
  148.             }  finally {  
  149.   
  150.                 if(post!=null){  
  151.                       
  152.                     post.releaseConnection();                 
  153.                 }  
  154.             }  
  155.         }  
  156.     }  
  157.     @Override  
  158.     public void saveLoginUserInfo(String homeCookieId,User userInfo){  
  159.           
  160.         try {  
  161.               
  162.             ActivationInfo info=memcachedClient.get(LOGOUT_PREFIX+homeCookieId);  
  163.               
  164.             if(info==null){  
  165.                   
  166.                 info=new ActivationInfo();  
  167.             }  
  168.               
  169.             info.setUserInfo(userInfo);  
  170.               
  171.             memcachedClient.set(LOGOUT_PREFIX+homeCookieId, Constant.MAX_USERINFO_INACTIVE_INTERVAL, info);  
  172.               
  173.         } catch (Exception e) {  
  174.               
  175.             throw new SSOException("#############  保存用户登陆信息失败 ",e);  
  176.         }  
  177.           
  178.           
  179.     }  
  180.     @Override  
  181.     public User getLoginUserInfo(String homeCookieId){  
  182.           
  183.         ActivationInfo info = null;  
  184.           
  185.         try {  
  186.             info=memcachedClient.get(LOGOUT_PREFIX+homeCookieId);  
  187.               
  188.             if(info!=null){  
  189.                   
  190.                 return info.getUserInfo();            
  191.             }  
  192.               
  193.             throw new RuntimeException("找不到该cookie:["+homeCookieId+"]的用户信息");  
  194.               
  195.         } catch (Exception e) {  
  196.               
  197.             throw new SSOException("############# 获取登陆用户信息失败 ####",e);  
  198.         }   
  199.           
  200.     }  
  201.   
  202.     @Override  
  203.     public boolean updateUserInfoTimeout(String homeCookieId) {  
  204.           
  205.         if(StringUtils.isBlank(homeCookieId)){  
  206.               
  207.             throw new IllegalArgumentException("homeCookieId 不可以为空!");  
  208.         }  
  209.           
  210.         try {  
  211.               
  212.             return memcachedClient.touch(LOGOUT_PREFIX+homeCookieId, Constant.MAX_USERINFO_INACTIVE_INTERVAL);  
  213.           
  214.         } catch (Exception e) {  
  215.               
  216.             LOGGER.error("############ 定时更新主站登陆用户信息失败 ",e);  
  217.         }   
  218.         return false;  
  219.   
  220.     }  
  221.       
  222. }  



2.客户端代码

(3)过滤器代码

[java] view plain copy
 
  1. package com.ffcs.sso.filter;  
  2.   
  3. import java.io.IOException;  
  4. import java.net.URLEncoder;  
  5. import java.util.Iterator;  
  6. import java.util.Map;  
  7. import java.util.Map.Entry;  
  8.   
  9. import javax.servlet.Filter;  
  10. import javax.servlet.FilterChain;  
  11. import javax.servlet.FilterConfig;  
  12. import javax.servlet.ServletException;  
  13. import javax.servlet.ServletRequest;  
  14. import javax.servlet.ServletResponse;  
  15. import javax.servlet.http.HttpServletRequest;  
  16. import javax.servlet.http.HttpServletResponse;  
  17. import javax.servlet.http.HttpSession;  
  18.   
  19. import org.apache.commons.lang.StringUtils;  
  20. import org.apache.http.client.methods.HttpGet;  
  21. import org.apache.http.client.methods.HttpPut;  
  22. import org.slf4j.Logger;  
  23. import org.slf4j.LoggerFactory;  
  24.   
  25. import com.ffcs.sso.exception.HttpRequestException;  
  26. import com.ffcs.sso.pojo.TicketResponseInfo;  
  27. import com.ffcs.sso.utils.Constant;  
  28. import com.ffcs.sso.utils.HttpClientUtils;  
  29. import com.ffcs.sso.utils.JsonUtil;  
  30.   
  31. public class SSOFilter implements Filter {  
  32.       
  33.     private final static Logger LOGGER=LoggerFactory.getLogger(SSOFilter.class);  
  34.   
  35.     private String ticketValidateURL;  
  36.       
  37.     private String redirectLoginURL;  
  38.       
  39.     private String updateUserInfoTimeOutURL;  
  40.   
  41.     @Override  
  42.     public void destroy() {  
  43.           
  44.     }  
  45.   
  46.     @Override  
  47.     public void doFilter(ServletRequest req, ServletResponse res, FilterChain chain) throws IOException, ServletException {  
  48.           
  49.         HttpServletRequest request = (HttpServletRequest) req;  
  50.           
  51.         HttpServletResponse response = (HttpServletResponse) res;  
  52.           
  53.         HttpSession session=request.getSession();  
  54.           
  55.         if(session.getAttribute(Constant.SSO_IS_LOGIN)==null){  
  56.           
  57.             String targetUrl = request.getRequestURL().toString();  
  58.   
  59.             String ticket = request.getParameter(Constant.SSO_TICKET);        
  60.               
  61.             //子站单点退出路径  
  62.               
  63.             String subLogoutPath = request.getScheme()+"://"+request.getServerName()+":"  
  64.                       
  65.                         +request.getServerPort()+ request.getContextPath() +"/"+Constant.SSO_LOGOUT_SUFFIX;  
  66.                    
  67.             TicketResponseInfo responseInfo=new TicketResponseInfo(false);  
  68.               
  69.             if(StringUtils.isNotBlank(ticket)){  
  70.                   
  71.                 //校验票如果校验通过同时保存子站的登出信息(减少提交次数,原本验证成功后在提交登出信息),并返回主站的cookieId和主站登陆的账号  
  72.                   
  73.                 responseInfo=validateTicketInfo(ticket,targetUrl,Constant.SSO_SUB_COOKIE_NAME,session.getId(),subLogoutPath);  
  74.             }  
  75.   
  76.             if(!responseInfo.isSuccess()){  
  77.                   
  78.                 String queryParams =this.getQureyParams(request);  
  79.   
  80.                 String params=StringUtils.isNotBlank(queryParams)?"&queryParams="+URLEncoder.encode(queryParams,"UTF-8"):"";  
  81.                   
  82.                 //重定向到主站判断系统是否登陆过  
  83.                   
  84.                 response.sendRedirect(redirectLoginURL + "?targetUrl=" + targetUrl + params);  
  85.                       
  86.                 LOGGER.debug("############## 重定向到主系统:" + redirectLoginURL + "?targetUrl=" + targetUrl + params);                      
  87.                   
  88.                 return;  
  89.             }  
  90.               
  91.             session.setAttribute(Constant.SSO_IS_LOGIN, true);  
  92.               
  93.             session.setAttribute(Constant.SSO_ACCOUNT, responseInfo.getAccount());  
  94.               
  95.             session.setAttribute(Constant.SSO_HOME_COOKIEID, responseInfo.getHomeCookieId());     
  96.         }  
  97.   
  98.         Long updateInterval = (System.currentTimeMillis() - session.getLastAccessedTime()) / 1000;  
  99.           
  100.         if( updateInterval > Constant.SSO_HOME_USERINFO_UPDATE_TIMEOUT){  
  101.               
  102.             //更新主站用户信息超时时间  
  103.               
  104.             updateUserInfoTimeOut((String)session.getAttribute(Constant.SSO_HOME_COOKIEID));  
  105.                   
  106.             LOGGER.debug("############## 更新主站用户信息超时时间,间隔{}秒   ########",Constant.SSO_HOME_USERINFO_UPDATE_TIMEOUT);                   
  107.       
  108.         }  
  109.           
  110.         chain.doFilter(request, response);  
  111.                   
  112.         return;  
  113.     }  
  114.   
  115.     private String getQureyParams(HttpServletRequest request) {  
  116.           
  117.         StringBuilder queryParams=new StringBuilder();  
  118.           
  119.         Map<String,String[]> map=request.getParameterMap();  
  120.           
  121.         Iterator<Entry<String, String[]>>  params=map.entrySet().iterator();  
  122.           
  123.         boolean tag=false;  
  124.           
  125.         while (params.hasNext()) {  
  126.               
  127.             Map.Entry<String,String[]> entry = params.next();  
  128.               
  129.             if(!entry.getKey().equals(Constant.SSO_TICKET)){  
  130.                   
  131.                 String[] values=entry.getValue();  
  132.                   
  133.                 for(String value:values){  
  134.   
  135.                     if(tag){  
  136.                           
  137.                         queryParams.append("&");  
  138.                     }  
  139.                     queryParams.append(entry.getKey()).append("=").append(value);                         
  140.                 }  
  141.                 tag=true;  
  142.             }  
  143.         }  
  144.         return queryParams.toString();  
  145.     }  
  146.       
  147.     private void updateUserInfoTimeOut(String homeCookieId){  
  148.       
  149.         HttpPut put=new HttpPut(updateUserInfoTimeOutURL);  
  150.           
  151.         //添加cookie主站那边能够找到session  
  152.           
  153.         put.setHeader("Cookie",Constant.SSO_HOME_COOKIE_NAME+"="+homeCookieId);  
  154.           
  155.         put.setHeader("accept", "text/plain; charset=UTF-8");  
  156.           
  157.         try {  
  158.               
  159.             HttpClientUtils.getResponse(put);  
  160.               
  161.         } catch (HttpRequestException e) {  
  162.               
  163.             LOGGER.error("###################### 定时更新主站用户信息失败 ",e);  
  164.         }  
  165.     }  
  166.   
  167.     /** 
  168.      * 根据ticket验证是否正确,验证通过返回主站的cookieId 
  169.      *  
  170.      * @param ticket 
  171.      *  
  172.      * @param target 
  173.      *  
  174.      * @return  返回验证空失败  成功cookieId 
  175.      */  
  176.     private TicketResponseInfo validateTicketInfo(String ticket, String target,String subCookieName,  
  177.               
  178.             String subCookieId, String subLogoutPath) {  
  179.           
  180.         HttpGet httpget = new HttpGet(ticketValidateURL + "/"+ ticket + "?target=" + target  
  181.                   
  182.                 +"&subCookieId="+subCookieId+"&subCookieName="+subCookieName+"&subLogoutPath="+subLogoutPath);  
  183.           
  184.         httpget.setHeader("accept", "application/json; charset=UTF-8");  
  185.           
  186.         String result;  
  187.           
  188.         try {  
  189.               
  190.             result = HttpClientUtils.getResponse(httpget);  
  191.               
  192.             return JsonUtil.fromJson(result, TicketResponseInfo.class);  
  193.               
  194.         } catch (HttpRequestException e) {  
  195.               
  196.             throw new RuntimeException("############### 子站验证ticket失败  ",e);  
  197.         }     
  198.           
  199.           
  200.     }  
  201.   
  202.     @Override  
  203.     public void init(FilterConfig filterConfig) {  
  204.           
  205.         if (filterConfig != null) {  
  206.               
  207.             LOGGER.info("#######   SSOFilter:Initializing filter");  
  208.         }  
  209.           
  210.         this.ticketValidateURL = filterConfig.getInitParameter("ticketValidateURL");  
  211.           
  212.         this.redirectLoginURL=filterConfig.getInitParameter("redirectLoginURL");  
  213.   
  214.         this.updateUserInfoTimeOutURL=filterConfig.getInitParameter("updateUserInfoTimeOutURL");  
  215.     }  
  216.       
  217. }  


(2)登出过滤器代码(比较简单,服务端通过httpclient回调这个路口进行退出,服务端必须把客户端登陆的cookie返回过来,不然找不到session)

[java] view plain copy
 
  1. package com.ffcs.sso.filter;  
  2.   
  3. import java.io.IOException;  
  4.   
  5. import javax.servlet.Filter;  
  6. import javax.servlet.FilterChain;  
  7. import javax.servlet.FilterConfig;  
  8. import javax.servlet.ServletException;  
  9. import javax.servlet.ServletRequest;  
  10. import javax.servlet.ServletResponse;  
  11. import javax.servlet.http.HttpServletRequest;  
  12.   
  13. public class LogoutFilter implements Filter{  
  14.       
  15.     @Override  
  16.     public void destroy() {  
  17.           
  18.           
  19.     }  
  20.   
  21.     @Override  
  22.     public void doFilter(ServletRequest req, ServletResponse res,FilterChain chain) throws IOException, ServletException {  
  23.           
  24.         HttpServletRequest request = (HttpServletRequest) req;  
  25.           
  26.         request.getSession().invalidate();  
  27.           
  28.         return;  
  29.           
  30.     }  
  31.   
  32.     @Override  
  33.     public void init(FilterConfig filterConfig) {  
  34.   
  35.     }  
  36.       
  37. }  


(3)客户端web.xml配置

[java] view plain copy
 
  1. <?xml version="1.0" encoding="UTF-8"?>  
  2. <web-app xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance"  
  3.     xmlns="http://java.sun.com/xml/ns/javaee" xmlns:web="http://java.sun.com/xml/ns/javaee"  
  4.     xsi:schemaLocation="http://java.sun.com/xml/ns/javaee http://java.sun.com/xml/ns/javaee/web-app_3_0.xsd"  
  5.     version="3.0">  
  6.     <filter>  
  7.         <filter-name>DisableUrlSessionFilter</filter-name>  
  8.         <filter-class>com.ffcs.sso.filter.DisableUrlSessionFilter</filter-class>  
  9.     </filter>  
  10.     <filter-mapping>  
  11.         <filter-name>DisableUrlSessionFilter</filter-name>  
  12.         <url-pattern>/*</url-pattern>  
  13.     </filter-mapping>  
  14.   
  15.     <filter>  
  16.         <filter-name>sessionFilter</filter-name>  
  17.         <filter-class>org.springframework.web.filter.DelegatingFilterProxy</filter-class>  
  18.     </filter>  
  19.     <filter-mapping>  
  20.         <filter-name>sessionFilter</filter-name>  
  21.         <url-pattern>/*</url-pattern>  
  22.     </filter-mapping>  
  23.   
  24.     <filter>  
  25.         <filter-name>LogoutFilter</filter-name>  
  26.         <filter-class>com.ffcs.sso.filter.LogoutFilter</filter-class>  
  27.     </filter>  
  28.     <filter-mapping>  
  29.         <filter-name>LogoutFilter</filter-name>  
  30.         <url-pattern>/SSO_LOGOUT</url-pattern>  
  31.     </filter-mapping>  
  32.     <listener>  
  33.         <description>spring监听器</description>  
  34.         <listener-class>org.springframework.web.context.ContextLoaderListener</listener-class>  
  35.     </listener>  
  36.     <listener>  
  37.         <listener-class>org.springframework.web.util.IntrospectorCleanupListener</listener-class>  
  38.     </listener>  
  39.     <context-param>  
  40.         <param-name>contextConfigLocation</param-name>  
  41.         <param-value>classpath:spring.xml</param-value>  
  42.     </context-param>  
  43.   
  44.     <filter>  
  45.         <description>字符集过滤器</description>  
  46.         <filter-name>encodingFilter</filter-name>  
  47.         <filter-class>org.springframework.web.filter.CharacterEncodingFilter</filter-class>  
  48.         <init-param>  
  49.             <description>字符集编码</description>  
  50.             <param-name>encoding</param-name>  
  51.             <param-value>UTF-8</param-value>  
  52.         </init-param>  
  53.     </filter>  
  54.     <filter-mapping>  
  55.         <filter-name>encodingFilter</filter-name>  
  56.         <url-pattern>/*</url-pattern>  
  57.     </filter-mapping>  
  58.   
  59.     <filter>  
  60.         <filter-name>SSOFilter</filter-name>  
  61.         <filter-class>com.ffcs.sso.filter.SSOFilter</filter-class>  
  62.         <init-param>  
  63.             <!-- 获取票保存的信息 ,并发送单点登陆子站信息  GET方式 -->  
  64.             <param-name>ticketValidateURL</param-name>   
  65.             <param-value>http://127.0.0.1:8080/SSO/webservice/ticket</param-value>  
  66.         </init-param>  
  67.         <init-param>  
  68.             <!-- 定时更新主站用户超时信息,防止子站用户没过期,主站登陆信息已经过期  PUT方式 -->  
  69.             <param-name>updateUserInfoTimeOutURL</param-name>  
  70.             <param-value>http://127.0.0.1:8080/SSO/webservice/userinfo/timeout</param-value>  
  71.         </init-param>  
  72.         <init-param>  
  73.             <!-- 重定向获取 -->  
  74.             <param-name>redirectLoginURL</param-name>  
  75.             <param-value>http://127.0.0.1:8080/SSO/redirect</param-value>  
  76.         </init-param>  
  77.     </filter>  
  78.     <filter-mapping>  
  79.         <filter-name>SSOFilter</filter-name>  
  80.         <url-pattern>/*</url-pattern>  
  81.     </filter-mapping>  
  82.     <servlet>  
  83.         <servlet-name>springMvc</servlet-name>  
  84.         <servlet-class>org.springframework.web.servlet.DispatcherServlet</servlet-class>  
  85.         <init-param>  
  86.             <param-name>contextConfigLocation</param-name>  
  87.             <param-value>classpath:spring-mvc.xml</param-value>  
  88.         </init-param>  
  89.         <!-- <load-on-startup>1</load-on-startup> -->  
  90.     </servlet>  
  91.     <servlet-mapping>  
  92.         <servlet-name>springMvc</servlet-name>  
  93.         <url-pattern>/</url-pattern>  
  94.     </servlet-mapping>  
  95.   
  96.     <!-- 浏览器不支持put,delete等method,由该filter将/blog?_method=delete转换为标准的http delete方法 -->  
  97.     <filter>  
  98.         <filter-name>HiddenHttpMethodFilter</filter-name>  
  99.         <filter-class>org.springframework.web.filter.HiddenHttpMethodFilter</filter-class>  
  100.     </filter>  
  101.   
  102.     <filter-mapping>  
  103.         <filter-name>HiddenHttpMethodFilter</filter-name>  
  104.         <servlet-name>springMvc</servlet-name>  
  105.     </filter-mapping>  
  106.     <error-page>  
  107.         <error-code>404</error-code>  
  108.         <location>/error/404.jsp</location>  
  109.     </error-page>  
  110.     <error-page>  
  111.         <error-code>500</error-code>  
  112.         <location>/error/500.jsp</location>  
  113.     </error-page>  
  114. </web-app>  

 

ok基本差不多核心代码就这么多了,写的不好别拍砖,不好的大家请指点哈,有空在把session集群这块在发布上来这样加上nginx就能够进行集群了大笑大笑

 

肿么挂附件哟。。。。。。。。

原文地址:https://www.cnblogs.com/tdalcn/p/8343192.html