當咱們的網站採用分佈式部署系統時,每一個子系統擁有本身獨立的session,若是不實現session共享,當用戶切換系統訪問的時候,會不停的提示登陸,這對於用戶體驗是很是很差的。所以對於多個子系統的的訪問,爲了達到用戶登陸一次便可以訪問其餘各個子系統,咱們採用了sso單點登陸系統。以前文章介紹了單點登陸系統的實現功能1,如今咱們來看下當訪問子系統時如何攔截用戶,當用戶的session過時了,如何提示用戶登陸,這裏採用了SpringMVC的攔截器的實現。java
(1)當登陸頁面時,用戶登陸成功後,在頁面的首頁能夠顯示:某某,歡迎您訪問此網站。這時候咱們是將以前生成的用戶的token值寫入Cookie中,由於只要瀏覽器沒關,cookie就存在,當不設置cookie的過時時間時,瀏覽器關閉,cookie就消逝。將token的內容寫入cookie,而後咱們利用jsonp訪問sso系統的利用token讀取用戶信息。而後顯示在頁面便可。web
另外這裏還用到一個技術:就是分佈式系統的cookie的共享問題。這個將cookie的屬性domain設置成全局共享便可。即不一樣的子系統的域名是不一樣的,sso.taotao.com;search.taotao.com;咱們須要將其域名設置爲**.taotao.com,這樣能夠實現cookie的共享。redis
具體實現以下:spring
if (null != request) {// 設置域名的cookie String domainName = getDomainName(request); System.out.println(domainName); if (!"localhost".equals(domainName)) { cookie.setDomain(domainName); } } cookie.setPath("/"); response.addCookie(cookie); } catch (Exception e) { e.printStackTrace(); } } /** * 獲得cookie的域名 */ private static final String getDomainName(HttpServletRequest request) { String domainName = null; String serverName = request.getRequestURL().toString(); if (serverName == null || serverName.equals("")) { domainName = ""; } else { serverName = serverName.toLowerCase(); serverName = serverName.substring(7); final int end = serverName.indexOf("/"); serverName = serverName.substring(0, end); final String[] domains = serverName.split("\\."); int len = domains.length; if (len > 3) { // www.xxx.com.cn domainName = "." + domains[len - 3] + "." + domains[len - 2] + "." + domains[len - 1]; } else if (len <= 3 && len > 1) { // xxx.com or xxx.cn domainName = "." + domains[len - 2] + "." + domains[len - 1]; } else { domainName = serverName; } } if (domainName != null && domainName.indexOf(":") > 0) { String[] ary = domainName.split("\\:"); domainName = ary[0]; } return domainName; }
(2)當用戶訪問訂單系統的時候,若是用戶沒有登陸,這時候須要攔截用戶提示用戶登陸此係統。這時候用了攔截器的做用。json
package com.taotao.portal.interceptor; import javax.servlet.http.HttpServletRequest; import javax.servlet.http.HttpServletResponse; import org.springframework.beans.factory.annotation.Autowired; import org.springframework.web.servlet.HandlerInterceptor; import org.springframework.web.servlet.ModelAndView; import com.taotao.common.utils.CookieUtils; import com.taotao.pojo.TbUser; import com.taotao.portal.service.impl.UserServiceImpl; public class LoginInterceptor implements HandlerInterceptor { @Autowired private UserServiceImpl userService; //執行以前攔截 @Override public boolean preHandle(HttpServletRequest request, HttpServletResponse response, Object handler) throws Exception { /* handler執行以前攔截,根據true或者false來判斷是否攔截。 瀏覽器沒關,這個cookie就存在,也就說token在裏面,至於token的session是否有效,這個須要再判斷。 當用戶登陸子系統時,須要提示用戶進行登陸,這是好用到攔截器,攔截這個頁面,原理的具體實現是這樣的 第一步:當用戶訪問頁面時,判斷cookie中是否有該用戶的token。即先從cookie中獲取token對象。 * 第二步:根據token查詢用戶是否存在,調用sso的從token中查詢用戶的接口來查詢用戶(這個過程是先從redis中檢查token是否過時,若是過時則沒有用戶,須要登陸,若是沒有過時,則表示存在用戶,由於以前用戶信息寫入了redis) *經過查詢用戶,若是用戶存在,則放行,若是不存在,則進行攔截,則跳轉到sso的登陸系統,提示登陸 */ String token = CookieUtils.getCookieValue(request,"TT_TOKEN"); //根據token來獲取用戶的信息,調用sso接口 TbUser user= userService.getBySSO(token); //判斷用戶是否存在 if (user==null) { //若是用戶爲空,則攔截到登陸界面,頁面重定向到的登陸頁面 response.sendRedirect(userService.SSO_BASE_URL+userService.SSO_PAGE_LOGIN+"?redirect="+request.getRequestURL()); //response.sendRedirect(userService.SSO_BASE_URL + userService.SSO_PAGE_LOGIN + "?redirect=" + request.getRequestURL()); return false; } return true; } //以後攔截 @Override public void postHandle(HttpServletRequest request, HttpServletResponse response, Object handler, ModelAndView modelAndView) throws Exception { // handler執行以後攔截 } @Override public void afterCompletion(HttpServletRequest request, HttpServletResponse response, Object handler, Exception ex) throws Exception { // TODO Auto-generated method stub } }
調用sso根據token獲取用戶信息跨域
package com.taotao.portal.service.impl; import org.springframework.beans.factory.annotation.Value; import com.taotao.common.utils.HttpClientUtil; import com.taotao.common.utils.JsonUtils; import com.taotao.common.utils.TaotaoResult; import com.taotao.pojo.TbUser; import com.taotao.portal.service.UserService; //經過token來獲取用戶信息,須要調用sso的接口信息 public class UserServiceImpl implements UserService { @Value("${SSO_BASE_URL}") public String SSO_BASE_URL; @Value("${SSO_TOKEN_URL}") public String SSO_TOKEN_URL; @Value("${SSO_PAGE_LOGIN}") public String SSO_PAGE_LOGIN; //這是根據token獲取用戶信息 @Override public TbUser getBySSO(String token) {
//不一樣子系統之間的訪問,跨域訪問,利用httpclient來實現 String json = HttpClientUtil.doGet(SSO_BASE_URL+SSO_TOKEN_URL+token); TaotaoResult result=TaotaoResult.formatToPojo(json, TbUser.class); if (result!=null) { TbUser user=(TbUser) result.getData(); return user; } return null; } }
最後不要忘了重要的一步:在springMVC中配置攔截器。這個配置就關係到到了哪一個功能模塊,使用攔截器,好比咱們提交訂單的時候,若是用戶沒有登陸,則此處增長攔截器。由於攔截器是在咱們商城的大的一個客戶端,淘淘商城中至關於taotao-portal中,當咱們寫好了訂單服務的接口時,url是order/***,用httpclientUtil來調用訂單服務的接口,此時咱們在springMVC.xml配置文件中,設置攔截order,若是提交訂單時若是沒有登陸就會跳轉到登陸窗口。瀏覽器
只須要將這裏的cookie
在springMVC中配置攔截器:session