zoukankan      html  css  js  c++  java
  • session共享

    session共享

    一、session共享的目的

    session共享是为了解决负载均衡的时候session信息不能共享的问题; 即session不能跨服务器访问;

    session共享可以通过以下五种方式实现:

    1. 服务器文件同步(造成文件重复,资源浪费;不建议)
    2. session存数据库(加大数据库压力;不建议)
    3. 存放在cookie中(cookie不太安全, 不建议)
    4. ip_hash(如果是局域网的话会造成这个局域的所有用户ip_hash值都一样; 不建议)
    5. 存缓存(redis, 或者memcache; 推荐使用)

    二、 session共享的实现

    以采用redis实现为例:
    将session存储在redis中, 将cookie作用域设置在顶级域名上, 这样SessionID就可以在各个子系统之间共享;

    session共享实现逻辑如下:

    • Controller层, 用户登入后将token存入到cookie中
    /**
     * Controller层逻辑
     */
    @Controller
    public class UserController {
    	
    	@Autowired
    	private UserService userService;
    	@Value("${TOKEN_KEY}")
    	private String TOKEN_KEY; // 记录SessionID的cookie名字 
    
    	@RequestMapping(value="/user/login", method=RequestMethod.POST)
    	@ResponseBody
    	public ResponseResult login(String username, String password,
    			HttpServletResponse response, HttpServletRequest request) {
    		// 检验用户是否已经登入,若登入则返回400错误
    		String token = CookieUtils.getCookieValue(request, TOKEN_KEY);
    		// 通过token从redis中获取用户session
    		ResponseResult userByToken = userService.getUserByToken(token);
    		TbUser data = (TbUser)userByToken.getData();
    		if(data != null && data.getUsername().equals(username)) {
    			return ResponseResult.build(400, "用户已登入,请勿重复登入");
    		}
    		// 不是重复登入,则执行login方法
    		ResponseResult result = userService.login(username, password);
    		// 登入成功后写入cookie
    		if(result.getStatus() == 200) {
    			// 把token写入cookie
    			CookieUtils.setCookie(request, response, TOKEN_KEY, result.getData().toString());
    		}
    		return result;
    	}
    }
    
    • Service层, 用户登入, 调用login, 为用户生成token, 并以USER_SESSION:token为键, user对象的json串为值,存入到redis中;
    /**
     * Service层逻辑
     */
    @Service
    public class UserServiceImpl implements UserService{
    	@Autowired
    	private TbUserMapper userMapper;
    	@Autowired
    	private JedisClient jedisClient ;
    	
    	@Value("${USER_SESSION}")
    	private String USER_SESSION;
    	@Value("${SESSION_EXPIRE}")
    	private Integer SESSION_EXPIRE;
    
    	@Override
    	public ResponseResult getUserByToken(String token) {
    		String json = jedisClient.get(USER_SESSION + ":" + token);
    		if(StringUtils.isBlank(json)) {
    			return ResponseResult.build(400, "用户登入已过期,请重新登入");
    		}
    		// 重置Session过期时间
    		jedisClient.expire(USER_SESSION + ":" + token, SESSION_EXPIRE);
    		// 把json转成user对象
    		TbUser user = JsonUtils.jsonToPojo(json, TbUser.class);
    		return ResponseResult.ok(user);
    	}
    
    	@Override
    	public ResponseResult login(String userName, String password) {
    		// 判断用户名和密码是否正确
    		TbUser user = new TbUser();
    		user.setUsername(userName);
    		List<TbUser> list = userMapper.selectByRecord(user);
    		if(list == null || list.size() == 0) {
    			return ResponseResult.build(400, "用户名或密码不正确");
    		}
    		
    		TbUser resultUser = list.get(0);
    		// 校验密码是否正确
    		if(!DigestUtils.md5DigestAsHex(password.getBytes())
    				.equals(resultUser.getPassword())) {
    			return ResponseResult.build(400, "用户名或密码不正确");
    		}
    		
    		// 使用UUID生成token
    		String token = UUID.randomUUID().toString();
    		// 清空密码
    		resultUser.setPassword(null);
    		// 把用户信息保存到redis,key为token,value为用户信息。
    		jedisClient.set(USER_SESSION + ":" + token, JsonUtils.objectToJson(resultUser));
    		// 设置token过期时间
    		jedisClient.expire(USER_SESSION + ":" + token, SESSION_EXPIRE);
    		// 返回登入成功, 返回token
    		return ResponseResult.ok(token);
    	}
    }
    
    • CookieUtil, 设置cookie作用域顶级域名, 解决cookie跨域让子系统共享
    public final class CookieUtils {
        /**
         * 设置Cookie的值 不设置生效时间默认浏览器关闭即失效,也不编码
         */
        public static void setCookie(HttpServletRequest request, HttpServletResponse response, String cookieName,
                String cookieValue) {
            doSetCookie(request, response, cookieName, cookieValue, -1, true);
        }
    
        /**
         * 设置Cookie的值,并使其在指定时间内生效
         * @param cookieMaxage cookie生效的最大秒数
         */
        private static final void doSetCookie(HttpServletRequest request, HttpServletResponse response,
                String cookieName, String cookieValue, int cookieMaxage, boolean isEncode) {
            try {
                if (cookieValue == null) {
                    cookieValue = "";
                } else if (isEncode) {
                    cookieValue = URLEncoder.encode(cookieValue, "utf-8");
                }
                Cookie cookie = new Cookie(cookieName, cookieValue);
                if (cookieMaxage > 0)
                    cookie.setMaxAge(cookieMaxage);
                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的顶级域名
         */
        public 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;
        }
    }
    
  • 相关阅读:
    iconfont 引入后没有显示
    使用element-ui库时浏览器出现异常汉字(代码里找不到该汉字)
    ElementUI select 把整个option(对象)作为值
    不让浏览器history后退前进
    从IE浏览器链接跳转到谷歌浏览器方法
    mddir 可以生成项目工程结构
    Element-UI select 新加全部与多选互斥选择
    H5 video 常用属性
    a链接跳转报错 status为 canceled的解决办法
    学习计划与记录
  • 原文地址:https://www.cnblogs.com/jxkun/p/9388469.html
Copyright © 2011-2022 走看看