zoukankan      html  css  js  c++  java
  • CAS工程用redis集群存储票据ticket Spring整合

    maven jar包版本:

    <dependency>
    <groupId>redis.clients</groupId>
    <artifactId>jedis</artifactId>
    <version>2.9.0</version>
    </dependency>
    
    <groupId>org.springframework.data</groupId>
    <artifactId>spring-data-redis</artifactId>
    <version>1.7.4.RELEASE</version>
    
    <dependency>
    <groupId>org.springframework</groupId>
    <artifactId>spring-context</artifactId>
    <version>4.3.3.RELEASE</version>
    </dependency>

    1:RedisTemplate由来简介

    在网上没有找到redisTemplate操作redis集群的例子,所以只能自己动手,在这里简单说一下过程.首先既然redisTemplate依赖jedis,那我们可以认为他内部操作的就是jedis,同理,我们也可以认为他内部也能操作jedisCluster.接下来就在spring-data-redis的源码里面搜一下jedisCluster这个字符串,发现JedisClusterConnection和JedisConnectionFactory中出现了jedisCluster,有没有觉得JedisConnectionFactory很眼熟呢,对,就是配置文件中redisTemplate初始化时候需要用到的连接工厂.现在就可以直接看JedisConnectionFactory
    首先,我们来看JedisConnectionFactory,发现里面有一个属性就是jedisCluster,那就看看jedisCluster是如何被初始化的,看下图:



    我们可以先看这个方法,这个方法是从InitializingBean中实现的方法,是spring初始化bean的时候需要调用的.所以可以假装认为只要实例化了JedisConnectionFactory就可以实例化jedisCluster,但是不要忘了有一个条件,那就是clusterConfig不能为空,接下来我们找clusterConfig是如何被实例化的.发现JedisConnectionFactory有一个构造函数

    JedisConnectionFactory(RedisClusterConfiguration clusterConfig, JedisPoolConfig poolConfig).这下就好办了JedisPoolConfig我们本来就认识,RedisClusterConfiguration是需要我们实例化的,接下来就看看RedisClusterConfiguration,一进来RedisClusterConfiguration我们就能看到个好东西,见下图:

    我们可以看RedisClusterConfiguration的注释,虽然没有说明,但是光看格式,就大概能猜到这些东西应该是写到properties文件里面的,而构造函数的参数又正好是propertySource,很容易就能联想到ResourcePropertySource,接下来就简单了,直接开始开干了.

    2:cas工程中deployerConfigContext.xml配置文件中的改动(红色标注)

     
    <?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:context="http://www.springframework.org/schema/context"
    xmlns:p="http://www.springframework.org/schema/p"
    xmlns:c="http://www.springframework.org/schema/c"
    xmlns:aop="http://www.springframework.org/schema/aop"
    xmlns:tx="http://www.springframework.org/schema/tx"
    xmlns:util="http://www.springframework.org/schema/util"
    xmlns:sec="http://www.springframework.org/schema/security"
    xsi:schemaLocation="http://www.springframework.org/schema/beans http://www.springframework.org/schema/beans/spring-beans.xsd
    http://www.springframework.org/schema/tx http://www.springframework.org/schema/tx/spring-tx.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/security http://www.springframework.org/schema/security/spring-security.xsd
    http://www.springframework.org/schema/util http://www.springframework.org/schema/util/spring-util.xsd">
    
    <!-- 引入配置文件 -->
    <!-- <bean id="propertyConfigurer" -->
    <!-- class="org.springframework.beans.factory.config.PropertyPlaceholderConfigurer"> -->
    <!-- <property name="location" value="classpath:redis.properties" /> -->
    <!-- </bean> -->
    
    <util:map id="authenticationHandlersResolvers">
    <entry key-ref="proxyAuthenticationHandler" value-ref="proxyPrincipalResolver" />
    <entry key-ref="primaryAuthenticationHandler" value-ref="primaryPrincipalResolver" />
    </util:map>
    
    <util:list id="authenticationMetadataPopulators">
    <ref bean="successfulHandlerMetaDataPopulator" />
    <ref bean="rememberMeAuthenticationMetaDataPopulator" />
    </util:list>
    
    <bean id="attributeRepository" class="org.jasig.services.persondir.support.NamedStubPersonAttributeDao"
    p:backingMap-ref="attrRepoBackingMap" />
    
    <!-- <alias name="acceptUsersAuthenticationHandler" alias="primaryAuthenticationHandler" /> -->
    
    <!--begin 从数据库中的用户表中读取 -->
    <bean id="MD5PasswordEncoder" class="org.jasig.cas.authentication.handler.DefaultPasswordEncoder" autowire="byName"> 
    <constructor-arg value="MD5"/>
    </bean>
    <bean id="queryDatabaseAuthenticationHandler" name="primaryAuthenticationHandler" class="org.jasig.cas.adaptors.jdbc.QueryDatabaseAuthenticationHandler"> 
    <property name="passwordEncoder" ref="MD5PasswordEncoder"/>
    </bean>
    <alias name="dataSource" alias="queryDatabaseDataSource"/>
    <bean id="dataSource"
    class="com.mchange.v2.c3p0.ComboPooledDataSource"
    p:driverClass="com.mysql.jdbc.Driver"
    p:jdbcUrl="jdbc:mysql://192.168.103.169:3306/userdb?useUnicode=true&characterEncoding=UTF-8&zeroDateTimeBehavior=convertToNull"
    p:user="root"
    p:password="123"
    p:initialPoolSize="6"
    p:minPoolSize="6"
    p:maxPoolSize="18"
    p:maxIdleTimeExcessConnections="120"
    p:checkoutTimeout="10000"
    p:acquireIncrement="6"
    p:acquireRetryAttempts="5"
    p:acquireRetryDelay="2000"
    p:idleConnectionTestPeriod="30"
    p:preferredTestQuery="select 1"/>
    <!--end 从数据库中的用户表中读取 -->
    
    <alias name="personDirectoryPrincipalResolver" alias="primaryPrincipalResolver" />
    
    <util:map id="attrRepoBackingMap">
    <entry key="uid" value="uid" />
    <entry key="eduPersonAffiliation" value="eduPersonAffiliation" />
    <entry key="groupMembership" value="groupMembership" />
    <entry>
    <key><value>memberOf</value></key>
    <list>
    <value>faculty</value>
    <value>staff</value>
    <value>org</value>
    </list>
    </entry>
    </util:map>
    
    <alias name="serviceThemeResolver" alias="themeResolver" />
    
    <alias name="jsonServiceRegistryDao" alias="serviceRegistryDao" />
    
    <!-- <alias name="defaultTicketRegistry" alias="ticketRegistry" /> -->
    <!-- 票据保存方式及有效期设置 -->
    <alias name="redisTicketRegistry" alias="ticketRegistry" />
    <!-- <bean id="redisTicketRegistry" class="com.hivescm.cas.ticket.registry.RedisTicketRegistry" -->
    <!-- p:client-ref="ticketRedisTemplate" -->
    <!-- p:tgtTimeout="28800" -->
    <!-- p:stTimeout="10"/> -->
    <bean id="redisTicketRegistry" class="com.hivescm.cas.ticket.registry.RedisClusterTicketRegistry"
    p:client-ref="redisTemplate"
    p:tgtTimeout="28800"
    p:stTimeout="10"/>
    <!-- redis连接池 -->
    <!-- <bean id="jedisConnFactory" -->
    <!-- class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory" -->
    <!-- p:hostName="192.168.103.158" -->
    <!-- p:database="10" -->
    <!-- p:usePool="true"/> -->
    
    <!-- <bean id="ticketRedisTemplate" class="com.hivescm.cas.ticket.registry.TicketRedisTemplate" -->
    <!-- p:connectionFactory-ref="jedisConnFactory"/> -->
    <!-- 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: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 >
    <!-- <bean id="redisHttpSessionConfiguration" -->
    <!-- class="org.springframework.session.data.redis.config.annotation.web.http.RedisHttpSessionConfiguration"> -->
    <!-- 超时时间,默认1800秒 --> 
    <!-- <property name="maxInactiveIntervalInSeconds" value="1800" /> -->
    <!-- </bean> -->
    
    
    
    
    <alias name="ticketGrantingTicketExpirationPolicy" alias="grantingTicketExpirationPolicy" />
    <alias name="multiTimeUseOrTimeoutExpirationPolicy" alias="serviceTicketExpirationPolicy" />
    
    <alias name="anyAuthenticationPolicy" alias="authenticationPolicy" />
    <alias name="acceptAnyAuthenticationPolicyFactory" alias="authenticationPolicyFactory" />
    
    <bean id="auditTrailManager"
    class="org.jasig.inspektr.audit.support.Slf4jLoggingAuditTrailManager"
    p:entrySeparator="${cas.audit.singleline.separator:|}"
    p:useSingleLine="${cas.audit.singleline:false}"/>
    
    <alias name="neverThrottle" alias="authenticationThrottle" />
    
    <util:list id="monitorsList">
    <ref bean="memoryMonitor" />
    <ref bean="sessionMonitor" />
    </util:list>
    
    <alias name="defaultPrincipalFactory" alias="principalFactory" />
    <alias name="defaultAuthenticationTransactionManager" alias="authenticationTransactionManager" />
    <alias name="defaultPrincipalElectionStrategy" alias="principalElectionStrategy" />
    <alias name="tgcCipherExecutor" alias="defaultCookieCipherExecutor" />
    </beans>
     
    
     
    

      

    3: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
    

      

    4. CAS用redis集群存储ticket的自定义实现类:RedisClusterTicketRegistry.java

     
     

      

    package com.hivescm.cas.ticket.registry;
    
    import org.jasig.cas.ticket.ServiceTicket;
    import org.jasig.cas.ticket.Ticket;
    import org.jasig.cas.ticket.TicketGrantingTicket;
    import org.jasig.cas.ticket.registry.encrypt.AbstractCrypticTicketRegistry;
    import org.springframework.beans.factory.DisposableBean;
    import org.springframework.data.redis.core.RedisTemplate;
    
    import javax.validation.constraints.Min;
    import javax.validation.constraints.NotNull;
    import java.util.Collection;
    import java.util.HashSet;
    import java.util.Set;
    import java.util.concurrent.TimeUnit;
    
    /**
    * Key-value ticket registry implementation that stores tickets in redis keyed on the ticket ID.
    *
    * @author serv
    */
    public final class RedisClusterTicketRegistry extends AbstractCrypticTicketRegistry implements DisposableBean {
    
    private final static String TICKET_PREFIX = "CAS:TICKET:";
    
    /**
    * redis client.
    */
    @NotNull
    private RedisTemplate client;
    
    /**
    * TGT cache entry timeout in seconds.
    */
    @Min(0)
    private int tgtTimeout;
    
    /**
    * ST cache entry timeout in seconds.
    */
    @Min(0)
    private int stTimeout;
    
    public void setClient(RedisTemplate client) {
    this.client = client;
    }
    
    public void setTgtTimeout(int tgtTimeout) {
    this.tgtTimeout = tgtTimeout;
    }
    
    public void setStTimeout(int stTimeout) {
    this.stTimeout = stTimeout;
    }
    
    public RedisClusterTicketRegistry() {
    }
    
    /**
    * Creates a new instance using the given redis client instance, which is presumably configured via
    * <code>net.spy.redis.spring.redisClientFactoryBean</code>.
    *
    * @param client redis client.
    * @param ticketGrantingTicketTimeOut TGT timeout in seconds.
    * @param serviceTicketTimeOut ST timeout in seconds.
    */
    public RedisClusterTicketRegistry(final RedisTemplate client, final int ticketGrantingTicketTimeOut,
    final int serviceTicketTimeOut) {
    this.tgtTimeout = ticketGrantingTicketTimeOut;
    this.stTimeout = serviceTicketTimeOut;
    this.client = client;
    }
    
    protected void updateTicket(final Ticket ticket) {
    logger.debug("Updating ticket {}", ticket);
    try {
    String redisKey = this.getTicketRedisKey(ticket.getId());
    this.client.boundValueOps(redisKey).set(ticket, getTimeout(ticket), TimeUnit.SECONDS);
    } catch (final Exception e) {
    logger.error("Failed updating {}", ticket, e);
    }
    }
    
    public void addTicket(final Ticket ticket) {
    logger.debug("Adding ticket {}", ticket);
    try {
    String redisKey = this.getTicketRedisKey(ticket.getId());
    this.client.boundValueOps(redisKey).set(ticket, getTimeout(ticket), TimeUnit.SECONDS);
    } catch (final Exception e) {
    logger.error("Failed Adding {}", ticket, e);
    }
    }
    
    public boolean deleteTicket(final String ticketId) {
    logger.debug("Deleting ticket {}", ticketId);
    try {
    this.client.delete(this.getTicketRedisKey(ticketId));
    return true;
    } catch (final Exception e) {
    logger.error("Failed deleting {}", ticketId, e);
    }
    return false;
    }
    
    public Ticket getTicket(final String ticketId) {
    try {
    final Ticket t = (Ticket) this.client.boundValueOps(this.getTicketRedisKey(ticketId)).get();
    if (t != null) {
    return getProxiedTicketInstance(t);
    }
    } catch (final Exception e) {
    logger.error("Failed fetching {} ", ticketId, e);
    }
    return null;
    }
    
    /**
    * {@inheritDoc}
    * This operation is not supported.
    *
    * @throws UnsupportedOperationException if you try and call this operation.
    */
    public Collection<Ticket> getTickets() {
    Set<Ticket> tickets = new HashSet<Ticket>();
    Set<String> keys = this.client.keys(this.getPatternTicketRedisKey());
    for (String key : keys) {
    Ticket ticket = (Ticket) this.client.boundValueOps(key).get();
    if (ticket == null) {
    this.client.delete(key);
    } else {
    tickets.add(ticket);
    }
    }
    return tickets;
    }
    
    public void destroy() throws Exception {
    client.getConnectionFactory().getConnection().close();
    }
    
    @Override
    protected boolean needsCallback() {
    return true;
    }
    
    private int getTimeout(final Ticket t) {
    if (t instanceof TicketGrantingTicket) {
    return this.tgtTimeout;
    } else if (t instanceof ServiceTicket) {
    return this.stTimeout;
    }
    throw new IllegalArgumentException("Invalid ticket type");
    }
    
    //Add a prefix as the key of redis
    private String getTicketRedisKey(String ticketId) {
    return TICKET_PREFIX + ticketId;
    }
    
    // pattern all ticket redisKey
    private String getPatternTicketRedisKey() {
    return TICKET_PREFIX + "*";
    }
    }
    

      

  • 相关阅读:
    Vue父子组件传值之——访问根组件$root、$parent、$children和$refs
    js判断是否为ie浏览器,精确显示各个ie版本
    在JS/jQuery中,怎么触发input的keypress/keydown/keyup事件?
    HTML中a标签自动识别电话、邮箱
    如何彻底删除Mac磁盘中的文件
    使用Understand for Mac编写您的第一个API脚本
    如何将MacOS Catalina降级为Mojave
    macOS Catalina 10.15.1 发布 全新 Emoji、支持 AirPods Pro
    WingIDE Pro 7如何新建项目
    忘记MacBook密码的解决技巧!
  • 原文地址:https://www.cnblogs.com/lvgg/p/7002583.html
Copyright © 2011-2022 走看看