基于Redis的CAS集群

单点登录(SSO)是复杂应用系统的基本需求,Yale CAS是目前常用的开源解决方案。CAS认证中心,基于其特殊作用,自然会成为整个应用系统的核心,所有应用系统的认证工作,都将请求到CAS来完成。因此CAS服务器是整个应用的关键节点,CAS发生故障,所有系统都将陷入瘫痪。同时,CAS的负载能力要足够强,能够承担所有的认证请求响应。利用负载均衡和集群技术,不仅能克服CAS单点故障,同时将认证请求分布到多台CAS服务器上,有效减轻单台CAS服务器的请求压力。下面将基于CAS 3.4.5来讨论下CAS集群。

CAS的工作原理,主要是基于票据(Ticket)来实现的(参见 CAS基本原理)。CAS票据,存储在TicketRegistry中,因此要想实现CAS Cluster, 必须要多台CAS之间共享所有的Ticket,采用统一的TicketRegistry,可以达到此目的。  缺省的CAS实现中,TicketRegistry在内存中实现,不同的CAS服务器有自己单独的TicketRegistry,因此是不支持分布式集群的。但CAS提供了支持TicketRegistry分布式的接口 org.jasig.cas.ticket.registry.AbstractDistributedTicketRegistry,我们可以实现这个接口实现多台CAS服务器TicketRegistry共享,从而实现CAS集群。

同时,较新版本CAS使用SpringWebFlow作为认证流程,而webflow需要使用session存储流程相关信息,因此实现CAS集群,我们还得需要让不同服务器的session进行共享。

我们采用内存数据库Redis来实现TicketRegistry,让多个CAS服务器共用同一个TicketRegistry。同样方法,我们让session也存储在Redis中,达到共享session的目的。下面就说说如何用 Redis来实现TicketRegistry,我们使用Java调用接口Jedis来操作Redis,代码如下:

?


1

2

3

4

5

6

7

8

9

10

11

12

13

14

15

16

17

18

19

20

21

22

23

24

25

26

27

28

29

30

31

32

33

34

35

36

37

38

39

40

41

42

43

44

45

46

47

48

49

50

51

52

53

54

55

56

57

58

59

60

61

62

63

64

65

66

67

68

69

70

71

72

73

74

75

76

77

78

79

80

81

82

83

84

85

86

87

88

89

90

91

92

93

94

95

96

97

98

99

100

101

102

103

104

105

106

107

108

109

110

111

112

113

114

115

116

117

118

119

120

121

122

123

124

125

126

127

128

129

130

131

132

133

134

135

136

137

138

139

140

141

142

143

144

145

146

147

148

149

150

151

152

153

import java.io.ByteArrayInputStream; 

import java.io.ByteArrayOutputStream; 

import java.io.ObjectInputStream; 

import java.io.ObjectOutputStream; 

import java.util.Collection; 

  

import org.jasig.cas.ticket.Ticket; 

import org.jasig.cas.ticket.TicketGrantingTicket; 

import org.jasig.cas.ticket.registry.AbstractDistributedTicketRegistry; 

  

  

import redis.clients.jedis.Jedis; 

import redis.clients.jedis.JedisPool; 

import redis.clients.jedis.JedisPoolConfig; 

  

  

/* 

 *  TicketRegistry using Redis, to solve CAS Cluster. 

 *   

 *  @author ZL 

 *  

 */

  

public class RedisTicketRegistry extends AbstractDistributedTicketRegistry { 

  

      

    private static int redisDatabaseNum; 

    private static String hosts; 

    private static int port; 

         private static int st_time;  //ST最大空闲时间 

          private static int tgt_time; //TGT最大空闲时间 

      

    private static JedisPool cachePool; 

      

    static

      

        redisDatabaseNum = PropertiesConfigUtil.getPropertyInt("redis_database_num"); 

        hosts = PropertiesConfigUtil.getProperty("hosts"); 

        port = PropertiesConfigUtil.getPropertyInt("port"); 

        st_time = PropertiesConfigUtil.getPropertyInt("st_time"); 

        tgt_time = PropertiesConfigUtil.getPropertyInt("tgt_time"); 

        cachePool = new JedisPool(new JedisPoolConfig(), hosts, port); 

          

    

      

    public void addTicket(Ticket ticket) { 

              

        Jedis jedis = cachePool.getResource(); 

        jedis.select(redisDatabaseNum); 

          

                  int seconds = 0

  

                  String key = ticket.getId() ; 

          

        if(ticket instanceof TicketGrantingTicket){ 

            //key = ((TicketGrantingTicket)ticket).getAuthentication().getPrincipal().getId(); 

            seconds = tgt_time/1000

        }else

            seconds = st_time/1000

        

    

          

        ByteArrayOutputStream bos = new ByteArrayOutputStream(); 

        ObjectOutputStream oos = null

        try

            oos = new ObjectOutputStream(bos); 

            oos.writeObject(ticket); 

             

        }catch(Exception e){ 

            log.error("adding ticket to redis error."); 

        }finally

            try{  

                if(null!=oos) oos.close(); 

            }catch(Exception e){ 

                log.error("oos closing error when adding ticket to redis."); 

            

        

        jedis.set(key.getBytes(), bos.toByteArray()); 

        jedis.expire(key.getBytes(), seconds); 

          

        cachePool.returnResource(jedis); 

          

    

      

    public Ticket getTicket(final String ticketId) { 

        return getProxiedTicketInstance(getRawTicket(ticketId)); 

    

      

      

    private Ticket getRawTicket(final String ticketId) { 

          

        if(null == ticketId) return null

          

        Jedis jedis = cachePool.getResource(); 

        jedis.select(redisDatabaseNum); 

          

        Ticket ticket = null

          

        ByteArrayInputStream bais = new ByteArrayInputStream(jedis.get(ticketId.getBytes())); 

        ObjectInputStream ois = null

          

        try

            ois = new ObjectInputStream(bais); 

            ticket = (Ticket)ois.readObject();  

        }catch(Exception e){ 

            log.error("getting ticket to redis error."); 

        }finally

            try

                if(null!=ois)  ois.close(); 

            }catch(Exception e){ 

                log.error("ois closing error when getting ticket to redis."); 

            

        

          

        cachePool.returnResource(jedis); 

          

        return ticket; 

    

     

      

  

    public boolean deleteTicket(final String ticketId) { 

          

        if (ticketId == null) { 

            return false

        

          

          

        Jedis jedis = cachePool.getResource(); 

        jedis.select(redisDatabaseNum); 

              

        jedis.del(ticketId.getBytes()); 

          

        cachePool.returnResource(jedis); 

          

        return true;         

    

   

    public Collection<Ticket> getTickets() { 

          

        throw new UnsupportedOperationException("GetTickets not supported."); 

  

    

  

    protected boolean needsCallback() { 

        return false

    

      

    protected void updateTicket(final Ticket ticket) { 

        addTicket(ticket); 

    

   

}

同时,我们在ticketRegistry.xml配置文件中,将TicketRegistry实现类指定为上述实现。即修改下面的class值

?


1

2

3

4

5

    <!-- Ticket Registry -->

    <bean id="ticketRegistry" class="org.jasig.cas.util.RedisTicketRegistry" />

    

<!--     <bean id="ticketRegistry" class="org.jasig.cas.ticket.registry.DefaultTicketRegistry" />

 -->

因为使用了Redis的expire功能,注释掉如下代码:

?


1

2

3

4

5

6

7

8

9

10

11

12

<!-- TICKET REGISTRY CLEANER -->

lt;!--  <bean id="ticketRegistryCleaner" class="org.jasig.cas.ticket.registry.support.DefaultTicketRegistryCleaner"

    p:ticketRegistry-ref="ticketRegistry" /> 

  

<bean id="jobDetailTicketRegistryCleaner" class="org.springframework.scheduling.quartz.MethodInvokingJobDetailFactoryBean"

    p:targetObject-ref="ticketRegistryCleaner"

    p:targetMethod="clean" /> 

  

<bean id="triggerJobDetailTicketRegistryCleaner" class="org.springframework.scheduling.quartz.SimpleTriggerBean"

    p:jobDetail-ref="jobDetailTicketRegistryCleaner"

    p:startDelay="20000"

    p:repeatInterval="5000000" /> -->

通过上述实现TicketRegistry,多台CAS服务器就可以共用同一个 TicketRegistry。对于如何共享session,我们可以采用现成的第三方工具tomcat-redis-session-manager直接集成即可。对于前端web服务器(如nginx),做好负载均衡配置,将认证请求分布转发给后面多台CAS,实现负载均衡和容错目的。

时间: 2024-10-13 00:18:40

基于Redis的CAS集群的相关文章

基于redis的cas集群配置(转)

1.cas ticket统一存储 做cas集群首先需要将ticket拿出来,做统一存储,以便每个节点访问到的数据一致.官方提供基于memcached的方案,由于项目需要,需要做计入redis,根据官方例子改了一个基于redis版本的. public class RedisTicketRegistry extends AbstractDistributedTicketRegistry{ @NotNull private final RedisTemplate<String,Object> rei

基于redis的cas集群配置

1.cas ticket统一存储 做cas集群首先需要将ticket拿出来,做统一存储,以便每个节点访问到的数据一致.官方提供基于memcached的方案,由于项目需要,需要做计入redis,根据官方例子改了一个基于redis版本的. public class RedisTicketRegistry extends AbstractDistributedTicketRegistry{ @NotNull private final RedisTemplate<String,Object> rei

Redis中sentinel集群的搭建和Jedis测试 图文教程[三]

在前两篇Redis中sentinel集群的搭建和Jedis测试 图文教程[一] 和Redis中sentinel集群的搭建和Jedis测试 图文教程[二] 中分别简述了Redis中sentinel集群的搭建和Java代码的Jedis测试. 这篇主要来简单分析一下Redis-sentinel集群的原理,根据追踪sentinel信息来完成Redis-sentinel集群测试中的详细的原理分析.包括master-slave各个中的sentinel信息的分析,failover过程,master宕机后的le

Redis发布了集群版3.0.0 beta

Redis不是比较成熟的Memcache或者Mysql的替代品,是对于大型互联网类应用在架构上很好的补充.现在有越来越多的应用也在纷纷基于Redis做架构的改造. Redis已经发布集群版3.0.0beta,相信在不久的将来就会出稳定版本. redis cluster 集群规范 安装 Redis集群版3.0.0beta版的功能介绍如下: This is the first beta of Redis 3.0.0. Redis 3.0 features support for Redis Clus

Tomcat8+Redis+Nginx实现集群

Tomcat8.5.14+Redis+Nginx实现集群 知识点 1)什么是集群 集群是一组相互独立的.通过高速网络互联的计算机,它们构成了一个组,并以单一系统的模式加以管理. 说白了就是同一个业务,部署在多个服务器上. 2)集群所遇到的问题 session共享 基于NFS的Session共享 基于数据库的Session共享 基于Cookie的Session共享 基于缓存的Session共享(本次选用这种方式) 3)集群优点 提高性能 降低成本 提高可扩展性 增强可靠性 测试环境 JDK版本:J

基于prometheus监控k8s集群

本文建立在你已经会安装prometheus服务的基础之上,如果你还不会安装,请参考:prometheus多维度监控容器 如果你还没有安装库k8s集群,情参考: 从零开始搭建基于calico的kubenetes 前言 kubernetes显然已成为各大公司亲睐的容器编排工具,各种私有云公有云平台基于它构建,那么,我们怎么监控集群中的所有容器呢?目前有三套方案: heapster+influxDB heapster为k8s而生,它从apiserver获取节点信息,每个节点kubelet内含了cAdv

Tomcat:基于Apache+Tomcat的集群搭建

根据Tomcat的官方文档说明可以知道,使用Tomcat配置集群需要与其它Web Server配合使用才可以完成,典型的有Apache和IIS. 这里就使用Apache+Tomcat方式来完成基于Tomcat在集群配置. 软件准备 1)Apache HTTP Server: 使用百度搜索httpd-2.2.25-win32-x86-no_ssl.msi,应该可以找到很多相关的下载链接.这里也提供一个:http://vdisk.weibo.com/s/C3trk_uGGkrmc 2)Tomcat

基于Windows 配置 nginx 集群

1.下载 nginx 下载页面 : http://nginx.org/en/download.html 具体文件: http://nginx.org/download/nginx-1.7.0.zip 2.运行 nginx 解压第一步下载的 nginx-1.7.0.zip 压缩包 解压到 c:/nginx路径 2.1.修改监听端口 由于 80 端口已经配置IIS ,现修改nginx 监听端口 server { listen      80; 修改为 listen    5000; 2.2 .修改

Redis 3.0集群(二)

在Redis 3.0集群(一)中讲了Redis集群的基本搭建.这一节主要讲对Redis集群的操作. 添加Master节点到集群 按照Redis集群一的方式,创建端口为7006的新实例,并启动该实例 将7006添加到集群: redis-trib.rb add-node 127.0.0.1:7006 127.0.0.1:7000 node:新节点没有包含任何数据, 因为它没有包含任何slot.新加入的加点是一个主节点, 当集群需要将某个从节点升级为新的主节点时, 这个新节点不会被选中. 给新节点分配