分佈式系統登陸功能攔截器的實現以及cookie的共享問題(利用cookie實現session在分佈式系統的共享)

當咱們的網站採用分佈式部署系統時,每一個子系統擁有本身獨立的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

相關文章
相關標籤/搜索