基於Redis的CAS服務端集群


為了保證生產環境CAS(Central Authentication Service)認證服務的高可用,防止出現單點故障,我們需要對CAS Server進行集群部署。

CAS的Ticket默認是以Map的方式存儲在JVM內存中的,多個tomcat之間無法共享,因此我們可以使用MemCached或者Redis來存儲Ticket。MemCached的方式官方已經提供了解決方案,我們這里使用的是Redis,具體實現可以參考CAS的模塊:cas-server-integration-memcached。

1、pom.xml文件中加入依賴:

<dependency> <groupId>redis.clients</groupId> <artifactId>jedis</artifactId> <version>2.7.2</version> </dependency> <dependency> <groupId>org.springframework.data</groupId> <artifactId>spring-data-redis</artifactId> <version>1.6.0.RELEASE</version> </dependency>

2、參考:org.jasig.cas.ticket.registry.MemCacheTicketRegistry,重寫Ticket注冊類。

package com.***.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.AbstractDistributedTicketRegistry; 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.concurrent.TimeUnit; public final class RedisTicketRegistry extends AbstractDistributedTicketRegistry implements DisposableBean { /** Memcached client. */ @NotNull private final RedisTemplate<String, Object> redisTemplate; /** * TGT cache entry timeout in seconds. */ @Min(0) private final int tgtTimeout; /** * ST cache entry timeout in seconds. */ @Min(0) private final int stTimeout; public RedisTicketRegistry(RedisTemplate<String, Object> redisTemplate, int tgtTimeout, int stTimeout) { this.redisTemplate = redisTemplate; this.tgtTimeout = tgtTimeout; this.stTimeout = stTimeout; } @Override public void addTicket(Ticket ticket) { logger.debug("Adding ticket {}", ticket); try { this.redisTemplate.opsForValue().set(ticket.getId(),ticket, getTimeout(ticket), TimeUnit.SECONDS); } catch (Exception e) { logger.error("Failed adding {}", ticket, e); } } @Override public Ticket getTicket(String ticketId) { try { final Ticket t = (Ticket) this.redisTemplate.opsForValue().get(ticketId); if (t != null) { return getProxiedTicketInstance(t); } } catch (final Exception e) { logger.error("Failed fetching {} ", ticketId, e); } return null; } @Override public boolean deleteTicket(String ticketId) { if (ticketId == null) { return false; } final Ticket ticket = getTicket(ticketId); if (ticket == null) { return false; } logger.debug("Deleting ticket {}", ticketId); try { this.redisTemplate.delete(ticketId); } catch (final Exception e) { logger.error("Failed deleting {}", ticketId, e); } return false; } @Override protected void updateTicket(Ticket ticket) { logger.debug("Updating ticket {}", ticket); try { if(this.redisTemplate.hasKey(ticket.getId())) { this.redisTemplate.opsForValue().set(ticket.getId(), ticket, getTimeout(ticket), TimeUnit.SECONDS); } } catch (final Exception e) { logger.error("Failed updating {}", ticket, e); } } @Override public Collection<Ticket> getTickets() { throw new UnsupportedOperationException("GetTickets not supported."); } @Override protected boolean needsCallback() { return true; } @Override public void destroy() throws Exception { } /** * Gets the timeout value for the ticket. * * @param t the t * @return the timeout */ 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"); } }

3、修改“ticketRegistry.xml”,先刪除文件中原有的bean定義,包括ticketRegistry、ticketRegistryCleaner、jobDetailTicketRegistryCleaner和triggerJobDetailTicketRegistryCleaner,然后添加下面的代碼片段:

<bean id="ticketRegistry" class="com.***.cas.ticket.registry.RedisTicketRegistry"> <constructor-arg index="0" ref="redisTemplate" /> <constructor-arg index="1" value="1800" /> <constructor-arg index="2" value="10" /> </bean> <bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig"> <property name="maxIdle" value="200" /> <property name="testOnBorrow" value="true" /> </bean> <bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory"> <property name="hostName" value="${redis.host}"/> <property name="port" value="6379"/> <property name="poolConfig" ref="jedisPoolConfig"/> </bean> <bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate"> <property name="connectionFactory" ref="jedisConnectionFactory"/> </bean>

4、配置Tomcat集群,實現Session共享,參考:https://github.com/jcoleman/tomcat-redis-session-manager。

到此,基於Redis的CAS Server集群配置已經完成。

“CAS單點登錄初使用”

“CAS單點登錄與Shiro的集成”

“CAS單點登錄密碼加鹽的認證”

“CAS+Shiro實現單點退出”


免責聲明!

本站轉載的文章為個人學習借鑒使用,本站對版權不負任何法律責任。如果侵犯了您的隱私權益,請聯系本站郵箱yoyou2525@163.com刪除。



 
粵ICP備18138465號   © 2018-2025 CODEPRJ.COM