CAS工程用redis集羣存儲票據ticket Spring整合

maven jar包版本:html

<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有一個構造函數java

 

JedisConnectionFactory(RedisClusterConfiguration clusterConfig, JedisPoolConfig poolConfig).這下就好辦了JedisPoolConfig咱們原本就認識,RedisClusterConfiguration是須要咱們實例化的,接下來就看看RedisClusterConfiguration,一進來RedisClusterConfiguration咱們就能看到個好東西,見下圖:node

咱們能夠看RedisClusterConfiguration的註釋,雖然沒有說明,可是光看格式,就大概能猜到這些東西應該是寫到properties文件裏面的,而構造函數的參數又正好是propertySource,很容易就能聯想到ResourcePropertySource,接下來就簡單了,直接開始開幹了.mysql

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配置文件

 

 

 

  

#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

  

 

4. CAS用redis集羣存儲ticket的自定義實現類:RedisClusterTicketRegistry.javaweb

 

 

 

 

  

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 + "*";
}
}
相關文章
相關標籤/搜索