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


當我們的網站采用分布式部署系統時,每個子系統擁有自己獨立的session,如果不實現session共享,當用戶切換系統訪問的時候,會不停的提示登錄,這對於用戶體驗是非常不好的。因此對於多個子系統的的訪問,為了達到用戶登錄一次即可以訪問其他各個子系統,我們采用了sso單點登錄系統。之前文章介紹了單點登錄系統的實現功能1,現在我們來看下當訪問子系統時如何攔截用戶,當用戶的session過期了,如何提示用戶登錄,這里采用了SpringMVC的攔截器的實現。

(1)當登錄頁面時,用戶登錄成功后,在頁面的首頁可以顯示:某某,歡迎您訪問此網站。這時候我們是將之前生成的用戶的token值寫入Cookie中,因為只要瀏覽器沒關,cookie就存在,當不設置cookie的過期時間時,瀏覽器關閉,cookie就消逝。將token的內容寫入cookie,然后我們利用jsonp訪問sso系統的利用token讀取用戶信息。然后顯示在頁面即可。

  另外這里還用到一個技術:就是分布式系統的cookie的共享問題。這個將cookie的屬性domain設置成全局共享即可。即不同的子系統的域名是不同的,sso.taotao.com;search.taotao.com;我們需要將其域名設置為**.taotao.com,這樣可以實現cookie的共享。

具體實現如下:

   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)當用戶訪問訂單系統的時候,如果用戶沒有登錄,這時候需要攔截用戶提示用戶登錄此系統。這時候用了攔截器的作用。

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,如果提交訂單時如果沒有登錄就會跳轉到登錄窗口。

只需要將這里的

 

 

 在springMVC中配置攔截器:

 


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM