CAS Client集群环境的Session问题及解决方案 不能退出登录
casclient源代码下载链接:https://github.com/apereo/java-cas-client
cas官网链接:https://www.apereo.org/projects/cas
1.上面一篇引用别人的分析方案介绍,来描述了下项目中遇到的问题,现在介绍本人怎么解决的
2.本人项目中用的是改造了tomcat 做的session 共享
3.所以客户端请求退出,服务端根据TGT查看对应的ST进行请求客户端,通过nginx负载均衡,可能对应到另一台客户端服务器,但是我们的session是存入rediscluster,任意客户端可以根据sessionid取到这个,进行删除,这样session就没了。即在客户端配置的SingleSignOutFilter,需要在HashMapBackedSessionMappingStorage进行删除存入redis的session数据,这样就可以退出了,就是这个原理来处理这个退出登录问题
一.上代码依赖jar包
spring-data-redis-1.7.4.RELEASE.jar;jedis-2.9.0.jar;fastjson-1.2.31.jar;注意jar包版本
二.改造的HashMapBackedSessionMappingStorage类代码
package org.jasig.cas.client.session; /*
* agreements. See the NOTICE file distributed with this work
* for additional information regarding copyright ownership.
* Jasig licenses this file to you under the Apache License,
* Version 2.0 (the "License"); you may not use this file
* except in compliance with the License. You may obtain a
* copy of the License at the following location:
*
* http://www.apache.org/licenses/LICENSE-2.0
*
* Unless required by applicable law or agreed to in writing,
* software distributed under the License is distributed on an
* "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY
* KIND, either express or implied. See the License for the
* specific language governing permissions and limitations
* under the License.
*/ import java.util.HashMap;
import java.util.Map;
import java.util.concurrent.TimeUnit; import javax.annotation.Resource;
import javax.servlet.http.HttpSession; import org.jasig.cas.client.session.SessionMappingStorage;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.ApplicationContext;
import org.springframework.context.annotation.EnableMBeanExport;
import org.springframework.context.support.ClassPathXmlApplicationContext;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.stereotype.Component; /**
* HashMap backed implementation of SessionMappingStorage.
*
* @author Scott Battaglia
* @version $Revision$ $Date$
* @since 3.1
*
*/
public final class HashMapBackedSessionMappingStorage implements SessionMappingStorage { protected final transient Logger logger = LoggerFactory.getLogger(getClass()); private final static String CASCLIENT_PREFIX = "CASCLI:SESSIONID:";
private final static String CASCLIENT_MAPID_PREFIX = "CASCLI:MAPID:"; private int casTimeout=86400; private RedisTemplate redisTemplate=new RedisTemplate(); public RedisTemplate getRedisTemplate() {
return redisTemplate;
} public void setRedisTemplate(RedisTemplate redisTemplate) {
this.redisTemplate = redisTemplate;
} public HashMapBackedSessionMappingStorage(){
ApplicationContext ac =new ClassPathXmlApplicationContext("classpath:schemeone/xml/spring-core.xml");
setRedisTemplate((RedisTemplate)ac.getBean("redisTemplate"));
} @Override
public synchronized void addSessionById(String mappingId, HttpSession session) {
logger.debug("Adding ticket {}", session);
try {
String sessionRedisKey = this.getCasSessionRedisKey(session.getId());
String mappingIdRedisKey = this.getCasMappingIdRedisKey(mappingId);
this.redisTemplate.boundValueOps(sessionRedisKey).set(mappingId, casTimeout, TimeUnit.SECONDS);
this.redisTemplate.boundValueOps(mappingIdRedisKey).set(session.getId(), casTimeout, TimeUnit.SECONDS);
} catch (final Exception e) {
logger.error("Failed Adding {}", session, e);
}
} @Override
public synchronized void removeBySessionById(String sessionId) {
logger.debug("Attempting to remove Session=[{}]", sessionId); final String key =(String) this.redisTemplate.boundValueOps(this.getCasSessionRedisKey(sessionId)).get(); if (logger.isDebugEnabled()) {
if (key != null) {
logger.debug("Found mapping for session. Session Removed.");
} else {
logger.debug("No mapping for session found. Ignoring.");
}
}
this.redisTemplate.delete(this.getCasMappingIdRedisKey(key));
this.redisTemplate.delete(this.getCasSessionRedisKey(sessionId));
} @Override
public synchronized HttpSession removeSessionByMappingId(String mappingId) {
//先去取sessionid
final String sessionId=(String) this.redisTemplate.boundValueOps(this.getCasMappingIdRedisKey(mappingId)).get();
//final HttpSession session = (HttpSession) this.redisTemplate.boundValueOps(sessionId).get();
this.redisTemplate.delete(sessionId);
// if (session != null) {
// removeBySessionById(session.getId());
// }
// return session;
if (sessionId != null) {
removeBySessionById(sessionId);
}
return null;
} private String getCasSessionRedisKey( String sessionId) {
return CASCLIENT_PREFIX + sessionId;
} private String getCasMappingIdRedisKey(String mappingId) {
return CASCLIENT_MAPID_PREFIX + mappingId;
} }
三。redistemplteBean配置
<?xml version="1.0" encoding="UTF-8"?>
<beans xmlns="http://www.springframework.org/schema/beans"
xmlns:xsi="http://www.w3.org/2001/XMLSchema-instance" xmlns:aop="http://www.springframework.org/schema/aop"
xmlns:context="http://www.springframework.org/schema/context"
xmlns:util="http://www.springframework.org/schema/util"
xsi:schemaLocation="
http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
http://www.springframework.org/schema/aop http://www.springframework.org/schema/aop/spring-aop.xsd
http://www.springframework.org/schema/context http://www.springframework.org/schema/context/spring-context.xsd
http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd"> <!-- 扫描注解Bean -->
<context:component-scan base-package="com.hivescm" /> <aop:config proxy-target-class="true" /> <!-- 开启AOP监听 只对当前配置文件有效 -->
<aop:aspectj-autoproxy expose-proxy="true" /> <bean id="propertyConfigurer"
class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer">
<property name="locations">
<list>
<!-- <value>classpath:schemeone/properties/common/*.properties</value> -->
<value>classpath:schemeone/properties/common/redis.cluster.properties</value>
</list>
</property>
</bean>
<!-- jedis 配置 -->
<bean id="poolConfig" class="redis.clients.jedis.JedisPoolConfig" >
<!-- 最大空闲数 -->
<property name="maxIdle" value="${redis.maxIdle}" />
<!-- 最大建立连接等待时间 -->
<property name="maxWaitMillis" value="${redis.maxWait}" />
<!-- 是否在从池中取出连接前进行检验,如果检验失败,则从池中去除连接并尝试取出另一个 -->
<property name="testOnBorrow" value="${redis.testOnBorrow}" />
</bean> <!-- 配置文件加载 -->
<bean id="resourcePropertySource" class="org.springframework.core.io.support.ResourcePropertySource">
<constructor-arg name="name" value="redis.cluster.properties"/>
<constructor-arg name="resource" value="classpath:schemeone/properties/common/redis.cluster.properties"/>
</bean> <!-- redisCluster配置 -->
<bean id="redisClusterConfiguration" class="org.springframework.data.redis.connection.RedisClusterConfiguration">
<constructor-arg name="propertySource" ref="resourcePropertySource"/>
</bean> <!-- redis服务器中心 -->
<bean id="connectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" >
<constructor-arg name="clusterConfig" ref="redisClusterConfiguration"/>
<constructor-arg name="poolConfig" ref="poolConfig"/>
<property name="password" value="${redis.password}" />
<property name="timeout" value="${redis.timeout}" ></property>
</bean > <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate" >
<property name="connectionFactory" ref="connectionFactory" />
<!-- 如果不配置Serializer,那么存储的时候缺省使用String,如果用User类型存储,那么会提示错误User can't cast to String!! -->
<property name="keySerializer" >
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer" />
</property>
<property name="valueSerializer" >
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer" />
</property>
<property name="hashKeySerializer">
<bean class="org.springframework.data.redis.serializer.StringRedisSerializer"/>
</property>
<property name="hashValueSerializer">
<bean class="org.springframework.data.redis.serializer.JdkSerializationRedisSerializer"/>
</property>
</bean > </beans>
4.redis.cluster.properties
#redis\u4E2D\u5FC3
#redis\u7684\u670D\u52A1\u5668\u5730\u5740
redis.host=192.168.103.158
#redis\u7684\u670D\u52A1\u7AEF\u53E3
redis.port=6379
#\u5BC6\u7801
redis.password=
#\u6700\u5927\u7A7A\u95F2\u6570
redis.maxIdle=100
#\u6700\u5927\u8FDE\u63A5\u6570
redis.maxActive=300
#\u6700\u5927\u5EFA\u7ACB\u8FDE\u63A5\u7B49\u5F85\u65F6\u95F4
redis.maxWait=1000
#\u5BA2\u6237\u7AEF\u8D85\u65F6\u65F6\u95F4\u5355\u4F4D\u662F\u6BEB\u79D2
redis.timeout=100000
redis.maxTotal=1000
redis.minIdle=8
#\u660E\u662F\u5426\u5728\u4ECE\u6C60\u4E2D\u53D6\u51FA\u8FDE\u63A5\u524D\u8FDB\u884C\u68C0\u9A8C,\u5982\u679C\u68C0\u9A8C\u5931\u8D25,\u5219\u4ECE\u6C60\u4E2D\u53BB\u9664\u8FDE\u63A5\u5E76\u5C1D\u8BD5\u53D6\u51FA\u53E6\u4E00\u4E2A
redis.testOnBorrow=true #sentinel
#spring.redis.sentinel.node1.host=127.0.0.1
#spring.redis.sentinel.node2.host=127.0.0.1
#spring.redis.sentinel.node3.host=127.0.0.1
#spring.redis.sentinel.node1.port=26379
#spring.redis.sentinel.node2.port=26479
#spring.redis.sentinel.node3.port=26579
#sentinel #jediscluster
#cluster1.host.port=127.0.0.1:7000
#cluster2.host.port=127.0.0.1:7001
#cluster3.host.port=127.0.0.1:7002
#cluster4.host.port=127.0.0.1:7003
#cluster5.host.port=127.0.0.1:7004
#cluster6.host.port=127.0.0.1:7005
#cluster7.host.port=127.0.0.1:7006
#cluster8.host.port=127.0.0.1:7007
#jediscluster #rediscluster
#spring.redis.cluster.nodes=192.168.103.158:6379
spring.redis.cluster.nodes=192.168.103.174:6379,192.168.103.174:6389,192.168.103.174:6399,192.168.103.173:6379,192.168.103.173:6389,192.168.103.173:6399
spring.redis.cluster.max-redirects=3
CAS Client集群环境的Session问题及解决方案 不能退出登录的更多相关文章
- CAS Client集群环境的Session问题及解决方案介绍,下篇介绍作者本人项目中的解决方案代码
CAS Client集群环境的Session问题及解决方案 程序猿讲故事 2016-05-20 原文 [原创申明:文章为原创,欢迎非盈利性转载,但转载必须注明来源] 之前写过一篇文章,介绍单点登 ...
- CAS Client集群环境的Session问题及解决方案
[原创申明:文章为原创,欢迎非盈利性转载,但转载必须注明来源] 之前写过一篇文章,介绍单点登录的基本原理.这篇文章重点介绍开源单点登录系统CAS的登录和注销的实现方法.并结合实际工作中碰到的问题,探讨 ...
- redis内存分配管理与集群环境下Session管理
##################内存管理############### 1.Redis的内存管理 .与memcache不同,没有实现自己的内存池 .在2..4以前,默认使用标准的内存分配函数(li ...
- redis 与java的连接 和集群环境下Session管理
redis 的安装与设置开机自启(https://www.cnblogs.com/zhulina-917/p/11746993.html) 第一步: a) 搭建环境 引入 jedis jar包 co ...
- Nginx+PHP负载均衡集群环境中Session共享方案 - 运维笔记
在网站使用nginx+php做负载均衡情况下,同一个IP访问同一个页面会被分配到不同的服务器上,如果session不同步的话,就会出现很多问题,比如说最常见的登录状态. 下面罗列几种nginx负载均衡 ...
- 【SpringBoot】spring-session-data-redis 解决集群环境下session共享
为什么会产生Session共享问题 集群情况下,session保存在各自的服务器的tomcat中,当分发地址至不同服务时,导致sesson取不到,就会产生session共享问题. 解决方案 负载均 ...
- Spring+Quartz集群环境下定时调度的解决方案
集群环境可能出现的问题 在上一篇博客我们介绍了如何在自己的项目中从无到有的添加了Quartz定时调度引擎,其实就是一个Quartz 和Spring的整合过程,很容易实现,但是我们现在企业中项目通常都是 ...
- 集群环境下定时调度的解决方案之Quartz集群
集群环境可能出现的问题 在上一篇博客我们介绍了如何在自己的项目中从无到有的添加了Quartz定时调度引擎,其实就是一个Quartz 和Spring的整合过程,很容易实现,但是我们现在企业中项目通常都是 ...
- Tomcat集群环境下session共享方案 通过memcached 方法实现
对于web应用集群的技术实现而言,最大的难点就是:如何能在集群中的多个节点之间保持数据的一致性,会话(Session)信息是这些数据中最重要的一块.要实现这一点, 大体上有两种方式:一种是把所有Ses ...
随机推荐
- Spring源码阅读(一)
Spring通过配置文件或者注解对类实例进行加载管理.稍微思考,可以猜测spring加载过程肯定先把配置转化为统一的配置对象,再把通过配置对象生产类实例.阅读源码,我们也可以发现这个逻辑. sprin ...
- 设计模式之Template(模板)(转)
Template定义: 定义一个操作中算法的骨架,将一些步骤的执行延迟到其子类中. 其实Java的抽象类本来就是Template模式,因此使用很普遍.而且很容易理解和使用,我们直接以示例开始: pub ...
- ETL面试题集锦
1. What is a logical data mapping and what does it mean to the ETL team? 什么是逻辑数据映射?它对ETL项目组的作用是什么? 答 ...
- 和風いろはちゃんイージー / Iroha and Haiku (ABC Edition) (水水)
题目链接:http://abc042.contest.atcoder.jp/tasks/abc042_a Time limit : 2sec / Memory limit : 256MB Score ...
- ul点击li,增加样式
用户首次绑定后,需要选择一款头像 <!--imgList头像列表--><el-row class="regModel1"> <el-col :span ...
- git getting started
2019/4/25-- after committing to blessed. modify dependency file to download file so as to get latest ...
- django自定义错误响应
在做一个web时,总是会出现各种错误,如400.403.404.500等.一般开发都要做对应的处理,给一些友好提示,或返回一些公益广告等. 在Django中,默认提供了常见的错误处理方式,比如: ha ...
- MySQL日志详细说明
这片博文我们会详细说明MySQL本身的日志,不包含重做日志和undo日志(这两个日志是innodb存储引擎的日志). MySQL本身的日志有以下几种(MySQL5.7版本): 错误日志 慢查询日志 通 ...
- P2336 [SCOI2012]喵星球上的点名(后缀自动机+莫队+dfs序)
P2336 [SCOI2012]喵星球上的点名 名字怎么存?显然是后缀自动机辣 询问点到多少个喵喵喵其实就是 查询后缀自动机上parent树的一个子树 于是我们考虑莫队 怎么树上莫队呢 我们用dfs序 ...
- Java中的Volatile和synchronized的区别
Synchronized和Volatile四个不同点: 1.粒度不同,前者锁对象和类 ,后者针对变量2.syn阻塞,volatile线程不阻塞3.syn保证三大特性,volatile不保证原子性4.s ...