zoukankan      html  css  js  c++  java
  • 分布式系统登录功能拦截器的实现以及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中配置拦截器:

  • 相关阅读:
    jsp第七次作业
    jsp第二次作业
    第四次JSP作业
    软件测试练习第一次
    JSP第一次课后作业
    读信息
    购物商城
    页面跳转
    安卓第7周作业
    安卓第六周作业
  • 原文地址:https://www.cnblogs.com/fengli9998/p/6411036.html
Copyright © 2011-2022 走看看