在tomcat集群下利用redis实现单点登陆
场景:比如说我们要实现一个集群环境,无非是把多个项目部署到多个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实现单点登陆的更多相关文章
- 用redis实现TOMCAT集群下的session共享
上篇实现了 LINUX中NGINX反向代理下的TOMCAT集群(http://www.cnblogs.com/yuanjava/p/6850764.html) 这次我们在上篇的基础上实现session ...
- 集群下使用redis统一session处理
pom依赖(快照版): <dependency> <groupId>org.springframework.session</groupId> <artifa ...
- 利用Redis发布订阅完成tomcat集群下的消息通知
以下为个人想法,如果有说的不对的地方请各位大佬见谅! 这是博主的第一篇博客,可能排版以及一些描述有不合理的地方还请勿喷,希望大家尽可能的多给我这样的新人一些鼓励让我能在写博客的道路上走下去. 进入正题 ...
- Tomcat集群下获取memcached缓存对象数量,统计在线用户数据量
项目需要统计在线用户数量,系统部署在集群环境下,使用会话粘贴的方式解决Session问题.要想得到真实在线用户数,必须是所有节点的总和. 这里考虑使用memcached存放用户登录数据,key为use ...
- 什么是tomcat集群?
什么是tomcat集群? 利用nginx对请求进行分流,将请求分配给不同的tomcat去处理,减少每个tomcat的负载量,提高服务器的响应速度. 目标 实现高性能负载均衡的tomcat集群. 工具 ...
- linux下实现redis共享session的tomcat集群
为了实现主域名与子域名的下不同的产品间一次登录,到处访问的效果,因此采用rediss实现tomcat的集群效果.基于redis能够异步讲缓存内容固化到磁盘上,从而当服务器意外重启后,仍然能够让sess ...
- linux下利用httpd搭建tomcat集群,实现负载均衡
公司使用运营管理平台是单点tomcat,使用量大,或者导出较大的运营数据时,会造成平台不可用,现在需要搭建tomcat集群,调研后,决定使用apache的httpd来搭建tomcat集群.以下是搭建步 ...
- Tomcat 集群模式下 Session 更新 Bug (redis memcached 及tomcat自已的集群)
从 excel 中导入数据入系统,我们用的是先上传文件至服务器再分析所上传的文件逐行导入. 就是执行了一循环,在当前循环位置标识一下客户端就知道执行的进度了,以前的方式 是用 session.setA ...
- Tomcat集群环境下session共享方案 通过memcached 方法实现
对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式:一种是把所有Ses ...
随机推荐
- weex 开发踩坑日记--环境配置、安卓运行、adb、开发
环境配置方面 1.需要安装java和android环境,java的话一定要下载jdk而不是jre. 在"系统变量"新建一个变量名为JAVA_HOME的变量,变量值为你本地java的 ...
- git学习笔记——廖雪峰git教程
OK,先附上教程--廖雪峰的官方网站 友情连接:git官网 简介 这里我只想引用他的原文: Linus可以向BitMover公司道个歉,保证以后严格管教弟兄们,嗯,这是不可能的.实际情况是这样的: L ...
- java mail smtp port
https://www.tutorialspoint.com/javamail_api/javamail_api_smtp_servers.htm https://www.mkyong.com/jav ...
- const修饰符限定的常量
类型前加const修饰符限定变量为只读,称为常量,定义时必须初始化,且初始化后编译器不允许再修改常量的值. 一.常量的定义 const在类型前面 const int value: //value是co ...
- python3_列表、元组、集合、字典
列表list #列表的基本操作 >>> a=[] #创建空列表 >>> a = [0,1,2,3,4,5] #创建列表并初始化,列表是[]包含由逗号分隔的多个元素组 ...
- 二叉排序树类的: C++ 实现
#include<iostream> using namespace std; template<class T> struct TreeNode { T element; T ...
- sql server2005查询分析器显示行号方法
工具栏:工具--选项--文本编辑器---所有语言--右边复选框 行号 打上勾就ok了
- 将关系型数据库抽取成redis的思路
思路是 先把id抽取出来形成一个·list表示数量 然后再把表变成键值对形式把id当做成键
- BZOJ5361[Lydsy1805月赛]对称数——主席树+随机化
题目链接:https://www.lydsy.com/JudgeOnline/problem.php?id=5361 好神的一道题啊! 容易看出来是要用维护权值的数据结构,因此树链剖分首先pass掉. ...
- 最大获利 HYSBZ - 1497 (最大权闭合图)
最大权闭合图: 有向图,每个点有点权,点权可正可负.对于任意一条有向边i和j,选择了点i就必须选择点j,你需要选择一些点使得得到权值最大. 解决方法: 网络流 对于任意点i,如果i权值为正,s向i连容 ...