您的位置:首页 > 其它

分布式系统登录功能拦截器的实现以及cookie的共享问题(利用cookie实现session在分布式系统的共享)

2017-02-17 18:10 721 查看
当我们的网站采用分布式部署系统时,每个子系统拥有自己独立的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中配置拦截器:

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: 
相关文章推荐