ICode9

精准搜索请尝试: 精确搜索
首页 > 其他分享> 文章详细

CAS Client集群环境的Session问题及解决方案 不能退出登录

2022-05-13 17:04:06  阅读:198  来源: 互联网

标签:session String Session CAS redis Client import port redisTemplate


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

  

 

标签:session,String,Session,CAS,redis,Client,import,port,redisTemplate
来源: https://www.cnblogs.com/zany-hui/p/16267309.html

本站声明: 1. iCode9 技术分享网(下文简称本站)提供的所有内容,仅供技术学习、探讨和分享;
2. 关于本站的所有留言、评论、转载及引用,纯属内容发起人的个人观点,与本站观点和立场无关;
3. 关于本站的所有言论和文字,纯属内容发起人的个人观点,与本站观点和立场无关;
4. 本站文章均是网友提供,不完全保证技术分享内容的完整性、准确性、时效性、风险性和版权归属;如您发现该文章侵犯了您的权益,可联系我们第一时间进行删除;
5. 本站为非盈利性的个人网站,所有内容不会用来进行牟利,也不会利用任何形式的广告来间接获益,纯粹是为了广大技术爱好者提供技术内容和技术思想的分享性交流网站。

专注分享技术,共同学习,共同进步。侵权联系[81616952@qq.com]

Copyright (C)ICode9.com, All Rights Reserved.

ICode9版权所有