为了保证生产环境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实现单点退出”

基于Redis的CAS服务端集群的更多相关文章

  1. 基于Docker的Consul服务发现集群搭建

    在去年的.NET Core微服务系列文章中,初步学习了一下Consul服务发现,总结了两篇文章.本次基于Docker部署的方式,以一个Demo示例来搭建一个Consul的示例集群,最后给出一个HA的架 ...

  2. SpringCloud02 Eureka知识点、Eureka服务端和客户端的创建、Eureka服务端集群、Eureka客户端向集群的Eureka服务端注册

    1 Eureka知识点 按照功能划分: Eureka由Eureka服务端和Eureka客户端组成 按照角色划分: Eureka由Eureka Server.Service Provider.Servi ...

  3. zookeeper源码分析之五服务端(集群leader)处理请求流程

    leader的实现类为LeaderZooKeeperServer,它间接继承自标准ZookeeperServer.它规定了请求到达leader时需要经历的路径: PrepRequestProcesso ...

  4. 基于redis实现tomcat8的tomcat集群的session持久化实现(tomcat-redis-session-manager二次开发)

    前言: 本项目是基于jcoleman的tomcat-redis-session-manager二次开发版本 1.修改了小部分实现逻辑 2.去除对juni.jar包的依赖 3.去除无效代码和老版本tom ...

  5. No.1 CAS 之LDAP认证服务端集群配置

    建档日期:   2016/08/31 最后修改日期:   2016/12/09   1 概述 本文描述了CAS单点登录服务端配置的大概流程,希望抛砖引玉,帮助你完成CAS服务端的配置. 本文采用apa ...

  6. 深入学习Redis(5):集群

    前言 在前面的文章中,已经介绍了Redis的几种高可用技术:持久化.主从复制和哨兵,但这些方案仍有不足,其中最主要的问题是存储能力受单机限制,以及无法实现写操作的负载均衡. Redis集群解决了上述问 ...

  7. Redis高可用-主从,哨兵,集群

    主从复制 Master-Slave主从概念 同时运行多个redis服务端,其中一个作为主(master),其他的一个或多个作为从(slave),主从之间通过网络进行通讯,slave通过复制master ...

  8. 搜索服务Solr集群搭建 使用ZooKeeper作为代理层

    上篇文章搭建了zookeeper集群 那好,今天就可以搭建solr搜服服务的集群了,这个和redis 集群不同,是需要zk管理的,作为一个代理层 安装四个tomcat,修改其端口号不能冲突.8080~ ...

  9. 关于redis主从|哨兵|集群模式

    关于redis主从.哨兵.集群的介绍网上很多,这里就不赘述了. 一.主从 通过持久化功能,Redis保证了即使在服务器重启的情况下也不会损失(或少量损失)数据,因为持久化会把内存中数据保存到硬盘上,重 ...

随机推荐

  1. angularJS 过滤器 表单验证

    过滤器1.filter的作用就是接收一个输入,通过某个规则进行处理,然后返回处理后的结果,主要用于数据的格式化.2.内置过滤器(1)Currency(货币)将一个数值格式化为货币格式,默认为$(2)D ...

  2. oracle 32位和64位的问题

  3. 谈NOT IN和Exists

    表1: test001 select * from test001

  4. zookeeper选举代码分析

    本文将以zookeeper的3.4.6版本作为源码分析版本.主要的代码类包括QuorumPeerMain.QuorumPeer.FastLeaderElection.QuorumMaj等. 假设有a, ...

  5. dubbo源码分析二:服务发布

    本文将深入分析dubbo的服务发布涉及到的流程及主要类的代码.首先,我们先从类的关系图来看一下dubbo发布服务涉及到的相关类. 1.类图 上图展示了部分服务发布过程中需要使用到的类和接口,其中: s ...

  6. c#简单数组

    int[,] a=new int[,]{{1,2},{3,4},{5,6}};//二维数组 textbox.text=a[0,1];//=2 int[][] b={new int[]{1,2},new ...

  7. java參数传递机制浅析

    欢迎转载,转载请声明出处! ----------------------------------------- 前言: java语言中,參数的传递仅仅有一种机制.那就是值传递. 举例: 以下将通过几个 ...

  8. HDU-3473Minimum Sum

    Problem Description You are given N positive integers, denoted as x0, x1 ... xN-1. Then give you som ...

  9. rsync是类unix系统下的数据镜像备份工具

    http://baike.baidu.com/view/1183189.htm   Ubuntu安装: sudo apt-get install rsync RedHat: yum install r ...

  10. Unity3d Awake、OnEnable、Start生命周期

    Unity3d,Awake.OnEnable.Start,都是游戏开始运行前,所运行的方法. GameObject的Activity为true,脚本的enable为true时,其先后顺序为:Awake ...