场景:比如说我们要实现一个集群环境,无非是把多个项目部署到多个tomcat下,然后按照一定的算法,轮询什么的随机访问多个tomcat服务器,但是问题也会有许多,比如说,我们最开始是把登陆人的信息存放到session中,但是如果是集群的情况下,比如我第一次登陆,把信息存放到session里面,但是我第二次访问的时候,访问到了第二台服务器,第二台服务器里面没有session信息,我们还得再登陆一遍,问题显而易见,session数据共享的问题。

解决思路:我们不要把信息存放到服务器的session中,要存放到一个公共的容器中,这个容器我们采用redis,然后我们每次取用户信息都去redis里面取,这不就解决了。问题又出现了,我们知道redis是key,value的数据结构,value是json格式化的用户对象信息,key呢?key当然要不一样了,因为许多登陆用户的的信息都会存在redis里面。别忘了,每个session都会有一个sessionId,这个sessionId是服务器给我们自动生成的。最开始我们都是用的这个,而且cookie每次访问服务器也会携带这个sessionId,这不是解决了?我们用sessionId来当key,User来当value,然后把这个sessionId写到本地的cookie中,每次访问服务器都从本地的cookie中取得这个sessionId,然后有了key,不就得到value了么。

需要注意的是,既然是单点登陆,顾名思义就是我登陆了这个一级域名下的服务器,然后再登陆它下面的二级域名,三级域名都不需要登陆,那这个cookie存的时候也需要讲究一下,需要把这个cooike存放到顶级域名下,他下面的子域名也就能得到这个cookie了。比如说两个域名

a.lzh.com和b.lzh.com  要实现单点登陆,就要把cookie存放到  .lzh.com  下(注意前面的点),ok。思路有了。看代码吧!!!

代码中有许多工具类,估计提供的不全,不过如果你看懂了我上面说的,你也应该知道大概具体啥意思。因为如果把每个包含的代码都贴出来,真的是好多啊。重点是理解。我其他博客也有相关的工具类。自己找找嘛。

补充:还有每次访问服务器都要把reidis的时间重新设置半小时。这个利用过滤器来实现。很简单。

CookieUtil.java

package com.mmall.util;

import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils; import javax.servlet.http.Cookie;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse; /**
* Created by 敲代码的卡卡罗特
*/
@Slf4j
public class CookieUtil { private final static String COOKIE_DOMAIN = ".happymmall.com"; //顶级域名
private final static String COOKIE_NAME = "mmall_login_token"; //存放在本地cookie的key //根据request从cookie中读取token
public static String readLoginToken(HttpServletRequest request){
Cookie[] cks = request.getCookies();
if(cks != null){
for(Cookie ck : cks){
log.info("read cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
if(StringUtils.equals(ck.getName(),COOKIE_NAME)){
log.info("return cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
return ck.getValue();
}
}
}
return null;
} //X:domain=".happymmall.com"
//a:A.happymmall.com cookie:domain=A.happymmall.com;path="/"
//b:B.happymmall.com cookie:domain=B.happymmall.com;path="/"
//c:A.happymmall.com/test/cc cookie:domain=A.happymmall.com;path="/test/cc"
//d:A.happymmall.com/test/dd cookie:domain=A.happymmall.com;path="/test/dd"
//e:A.happymmall.com/test cookie:domain=A.happymmall.com;path="/test" //写入cookie
public static void writeLoginToken(HttpServletResponse response,String token){
Cookie ck = new Cookie(COOKIE_NAME,token);
ck.setDomain(COOKIE_DOMAIN);
ck.setPath("/");//代表设置在根目录
ck.setHttpOnly(true);
//单位是秒。
//如果这个maxage不设置的话,cookie就不会写入硬盘,而是写在内存。只在当前页面有效。
ck.setMaxAge(60 * 60 * 24 * 365);//如果是-1,代表永久
log.info("write cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
response.addCookie(ck);
} //删除cookie
public static void delLoginToken(HttpServletRequest request,HttpServletResponse response){
Cookie[] cks = request.getCookies();
if(cks != null){
for(Cookie ck : cks){
if(StringUtils.equals(ck.getName(),COOKIE_NAME)){
ck.setDomain(COOKIE_DOMAIN);
ck.setPath("/");
ck.setMaxAge(0);//设置成0,代表删除此cookie。
log.info("del cookieName:{},cookieValue:{}",ck.getName(),ck.getValue());
response.addCookie(ck);
return;
}
}
}
} }

UserController.java (用户登陆。退出方法)

/**
* 用户登录
* @param username
* @param password
* @param session
* @return
*/
@RequestMapping(value = "login.do",method = RequestMethod.POST)
@ResponseBody
public ServerResponse<User> login(String username, String password, HttpSession session, HttpServletResponse httpServletResponse){
ServerResponse<User> response = iUserService.login(username,password);
if(response.isSuccess()){ // session.setAttribute(Const.CURRENT_USER,response.getData());
CookieUtil.writeLoginToken(httpServletResponse,session.getId());
RedisShardedPoolUtil.setEx(session.getId(), JsonUtil.obj2String(response.getData()),Const.RedisCacheExtime.REDIS_SESSION_EXTIME); }
return response;
} @RequestMapping(value = "logout.do",method = RequestMethod.GET)
@ResponseBody
public ServerResponse<String> logout(HttpSession session,HttpServletRequest httpServletRequest,HttpServletResponse httpServletResponse){
String loginToken = CookieUtil.readLoginToken(httpServletRequest);
CookieUtil.delLoginToken(httpServletRequest,httpServletResponse);
RedisShardedPoolUtil.del(loginToken); // session.removeAttribute(Const.CURRENT_USER); return ServerResponse.createBySuccess();
}

SessionExpireFilter.java  (过滤器,每次访问服务器把redis的时间重置30分钟)

package com.mmall.controller.common;

import com.mmall.common.Const;
import com.mmall.pojo.User;
import com.mmall.util.CookieUtil;
import com.mmall.util.JsonUtil;
import com.mmall.util.RedisShardedPoolUtil;
import org.apache.commons.lang.StringUtils; import javax.servlet.Filter;
import javax.servlet.FilterChain;
import javax.servlet.FilterConfig;
import javax.servlet.ServletException;
import javax.servlet.ServletRequest;
import javax.servlet.ServletResponse;
import javax.servlet.http.HttpServletRequest;
import java.io.IOException; /**
* Created by 敲代码的卡卡罗特
*/
public class SessionExpireFilter implements Filter {
@Override
public void init(FilterConfig filterConfig) throws ServletException { } @Override
public void doFilter(ServletRequest servletRequest, ServletResponse servletResponse, FilterChain filterChain) throws IOException, ServletException {
HttpServletRequest httpServletRequest = (HttpServletRequest)servletRequest; String loginToken = CookieUtil.readLoginToken(httpServletRequest); if(StringUtils.isNotEmpty(loginToken)){
//判断logintoken是否为空或者"";
//如果不为空的话,符合条件,继续拿user信息 String userJsonStr = RedisShardedPoolUtil.get(loginToken);
User user = JsonUtil.string2Obj(userJsonStr,User.class);
if(user != null){
//如果user不为空,则重置session的时间,即调用expire命令
RedisShardedPoolUtil.expire(loginToken, Const.RedisCacheExtime.REDIS_SESSION_EXTIME);
}
}
filterChain.doFilter(servletRequest,servletResponse);
} @Override
public void destroy() { }
}

ok,代码省略许多工具类和细节,主要是思想。希望大家明白,我讲的够清楚了。

在tomcat集群下利用redis实现单点登陆的更多相关文章

  1. 用redis实现TOMCAT集群下的session共享

    上篇实现了 LINUX中NGINX反向代理下的TOMCAT集群(http://www.cnblogs.com/yuanjava/p/6850764.html) 这次我们在上篇的基础上实现session ...

  2. 集群下使用redis统一session处理

    pom依赖(快照版): <dependency> <groupId>org.springframework.session</groupId> <artifa ...

  3. 利用Redis发布订阅完成tomcat集群下的消息通知

    以下为个人想法,如果有说的不对的地方请各位大佬见谅! 这是博主的第一篇博客,可能排版以及一些描述有不合理的地方还请勿喷,希望大家尽可能的多给我这样的新人一些鼓励让我能在写博客的道路上走下去. 进入正题 ...

  4. Tomcat集群下获取memcached缓存对象数量,统计在线用户数据量

    项目需要统计在线用户数量,系统部署在集群环境下,使用会话粘贴的方式解决Session问题.要想得到真实在线用户数,必须是所有节点的总和. 这里考虑使用memcached存放用户登录数据,key为use ...

  5. 什么是tomcat集群?

    什么是tomcat集群? 利用nginx对请求进行分流,将请求分配给不同的tomcat去处理,减少每个tomcat的负载量,提高服务器的响应速度. 目标 实现高性能负载均衡的tomcat集群. 工具 ...

  6. linux下实现redis共享session的tomcat集群

    为了实现主域名与子域名的下不同的产品间一次登录,到处访问的效果,因此采用rediss实现tomcat的集群效果.基于redis能够异步讲缓存内容固化到磁盘上,从而当服务器意外重启后,仍然能够让sess ...

  7. linux下利用httpd搭建tomcat集群,实现负载均衡

    公司使用运营管理平台是单点tomcat,使用量大,或者导出较大的运营数据时,会造成平台不可用,现在需要搭建tomcat集群,调研后,决定使用apache的httpd来搭建tomcat集群.以下是搭建步 ...

  8. Tomcat 集群模式下 Session 更新 Bug (redis memcached 及tomcat自已的集群)

    从 excel 中导入数据入系统,我们用的是先上传文件至服务器再分析所上传的文件逐行导入. 就是执行了一循环,在当前循环位置标识一下客户端就知道执行的进度了,以前的方式 是用 session.setA ...

  9. Tomcat集群环境下session共享方案 通过memcached 方法实现

    对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式:一种是把所有Ses ...

随机推荐

  1. 8-Python3从入门到实战—基础之数据类型(集合-Sets)

    Python从入门到实战系列--目录 集合的定义 集合(set)和字典类似,也是一组key的集合,但不存储value:由于key不能重复,所以,在set中,没有重复的key. 创建一个set,需要提供 ...

  2. Aspose for Maven 使用

    https://blog.aspose.com/2014/08/12/aspose-for-maven-aspose-cloud-maven-repository/ https://marketpla ...

  3. 求两个整数的最大公约数GCM

    思路分析: (1)求差判定法:  如果两个数相差不大,可以用大数减去小数,所得的差与小数的最大公约数就是原来两个数的最大公约数.例如:求78和60的最大公约数.78-60=18,18和60的最大公约数 ...

  4. 日常工作: 应用服务器Oracle驱动问题说明

    1. .net使用Oracle驱动的发展等 作为.net线的产品的ERP产品 最初的版本 使用了.net 1.1发布时 微软提供的Oracle的驱动 但是后续微软的.net产品线貌似没有继续发展相应的 ...

  5. pxe+kickstart 自动化部署linux操作系统

    kickstart 是什么? 批量部署Linux服务器操作系统 运行模式: C/S client/server 服务器上要部署: DHCP tftp(非交互式文件共享) 安装系统的三个步骤: 1.加载 ...

  6. Lodop打印控件里SET_PRINT_STYLE和SET_PRINT_STYLEA

    LODOP.SET_PRINT_STYLE 对该语句后面的打印项样式设置效果.LODOP.SET_PRINT_STYLEA 针对第一个参数设置的打印项样式设置效果.这两个语句,作用范围不同. 在设置字 ...

  7. 如何判断使用的是Lodop还是C-Lodop

    Lodop和C-Lodop混合部署的时候,LodopFuncs.js里面有自动判断当前浏览器使用什么,支持np插件的就会使用Lodop,不支持插件方式的会使用C-Lodop,可以通过预览窗口左上角图标 ...

  8. FFT ip core

    The FFT core provides four architecture options to offer a trade-off权衡取舍 between core size andtransf ...

  9. BZOJ4541 HNOI2016矿区(平面图转对偶图)

    考虑先将平面图转化为对偶图.具体地,将无向边拆成两条有向边.每次考虑找到包围一个区域的所有边.对当前考虑的边,找到该边的反向边在该边终点的出边集中,按极角序排序的后继,这条后继边也是包围该区域的边.这 ...

  10. share.js轻松分享/邀请

    GitHub地址 https://github.com/overtrue/share.js 安装 安装的方法很多,大家选择自己合适的进行安装就好. clone $ git clone https:// ...