• 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

    #redisu4E2Du5FC3
    #redisu7684u670Du52A1u5668u5730u5740
    redis.host=192.168.103.158
    #redisu7684u670Du52A1u7AEFu53E3
    redis.port=6379
    #u5BC6u7801
    redis.password=
    #u6700u5927u7A7Au95F2u6570
    redis.maxIdle=100
    #u6700u5927u8FDEu63A5u6570
    redis.maxActive=300
    #u6700u5927u5EFAu7ACBu8FDEu63A5u7B49u5F85u65F6u95F4
    redis.maxWait=1000
    #u5BA2u6237u7AEFu8D85u65F6u65F6u95F4u5355u4F4Du662Fu6BEBu79D2
    redis.timeout=100000
    redis.maxTotal=1000
    redis.minIdle=8
    #u660Eu662Fu5426u5728u4ECEu6C60u4E2Du53D6u51FAu8FDEu63A5u524Du8FDBu884Cu68C0u9A8C,u5982u679Cu68C0u9A8Cu5931u8D25,u5219u4ECEu6C60u4E2Du53BBu9664u8FDEu63A5u5E76u5C1Du8BD5u53D6u51FAu53E6u4E00u4E2A
    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
    

      

  • 相关阅读:
    pip安装软件时出现Command "python setup.py egg_info" failed with error code 1 in /tmp/pip-build*的解决方案
    tidb安装
    TIDB 5.0 安装体验 怎么快速玩起来
    利用Tampermonkey(油猴)+ IDM 实现百度云盘大文件下载(IDM安装教程)
    python字典及相关操作
    【转载】CEO:我需要什么样的产品经理?
    2014年3月第三周/第一次跳槽、心情低潮期、与老总沟通问题
    hello word!
    function(event)中的event详解
    CSS 伪类
  • 原文地址:https://www.cnblogs.com/lvgg/p/7085867.html
Copyright © 2020-2023  润新知