文档章节

基于Redis的CAS集群

無雙
 無雙
发布于 2013/06/13 10:14
字数 1000
阅读 4236
收藏 17
点赞 0
评论 0

单点登录(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,代码如下:

 

[html]    view plain   copy  

  1. import java.io.ByteArrayInputStream;  

  2. import java.io.ByteArrayOutputStream;  

  3. import java.io.ObjectInputStream;  

  4. import java.io.ObjectOutputStream;  

  5. import java.util.Collection;  

  6.   

  7. import org.jasig.cas.ticket.Ticket;  

  8. import org.jasig.cas.ticket.TicketGrantingTicket;  

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

  10.   

  11.   

  12. import redis.clients.jedis.Jedis;  

  13. import redis.clients.jedis.JedisPool;  

  14. import redis.clients.jedis.JedisPoolConfig;  

  15.   

  16.   

  17. /*  

  18.  *  TicketRegistry using Redis, to solve CAS Cluster.  

  19.  *    

  20.  *  @author ZL  

  21.  *   

  22.  */  

  23.   

  24. public class RedisTicketRegistry extends AbstractDistributedTicketRegistry {  

  25.   

  26.       

  27.     private static int redisDatabaseNum;  

  28.     private static String hosts;  

  29.     private static int port;  

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

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

  32.       

  33.     private static JedisPool cachePool;  

  34.       

  35.     static {  

  36.       

  37.         redisDatabaseNum = PropertiesConfigUtil.getPropertyInt("redis_database_num");  

  38.         hosts = PropertiesConfigUtil.getProperty("hosts");  

  39.         port = PropertiesConfigUtil.getPropertyInt("port");  

  40.         st_time = PropertiesConfigUtil.getPropertyInt("st_time");  

  41.         tgt_time = PropertiesConfigUtil.getPropertyInt("tgt_time");  

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

  43.           

  44.     }  

  45.       

  46.     public void addTicket(Ticket ticket) {  

  47.               

  48.         Jedis jedis = cachePool.getResource();  

  49.         jedis.select(redisDatabaseNum);  

  50.           

  51.                   int seconds = 0;  

  52.   

  53.                   String key = ticket.getId() ;  

  54.           

  55.         if(ticket instanceof TicketGrantingTicket){  

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

  57.             seconds = tgt_time/1000;  

  58.         }else{  

  59.             seconds = st_time/1000;  

  60.         }  

  61.     

  62.           

  63.         ByteArrayOutputStream bos = new ByteArrayOutputStream();  

  64.         ObjectOutputStream oos = null;  

  65.         try{  

  66.             oos = new ObjectOutputStream(bos);  

  67.             oos.writeObject(ticket);  

  68.              

  69.         }catch(Exception e){  

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

  71.         }finally{  

  72.             try{   

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

  74.             }catch(Exception e){  

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

  76.             }  

  77.         }  

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

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

  80.           

  81.         cachePool.returnResource(jedis);  

  82.           

  83.     }  

  84.       

  85.     public Ticket getTicket(final String ticketId) {  

  86.         return getProxiedTicketInstance(getRawTicket(ticketId));  

  87.     }  

  88.       

  89.       

  90.     private Ticket getRawTicket(final String ticketId) {  

  91.           

  92.         if(null == ticketId) return null;  

  93.           

  94.         Jedis jedis = cachePool.getResource();  

  95.         jedis.select(redisDatabaseNum);  

  96.           

  97.         Ticket ticket = null;  

  98.           

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

  100.         ObjectInputStream ois = null;  

  101.           

  102.         try{  

  103.             ois = new ObjectInputStream(bais);  

  104.             ticket = (Ticket)ois.readObject();   

  105.         }catch(Exception e){  

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

  107.         }finally{  

  108.             try{  

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

  110.             }catch(Exception e){  

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

  112.             }  

  113.         }  

  114.           

  115.         cachePool.returnResource(jedis);  

  116.           

  117.         return ticket;  

  118.     }  

  119.      

  120.       

  121.   

  122.     public boolean deleteTicket(final String ticketId) {  

  123.           

  124.         if (ticketId == null) {  

  125.             return false;  

  126.         }  

  127.           

  128.           

  129.         Jedis jedis = cachePool.getResource();  

  130.         jedis.select(redisDatabaseNum);  

  131.               

  132.         jedis.del(ticketId.getBytes());  

  133.           

  134.         cachePool.returnResource(jedis);  

  135.           

  136.         return true;          

  137.     }  

  138.    

  139.     public Collection<Ticket> getTickets() {  

  140.           

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

  142.   

  143.     }  

  144.   

  145.     protected boolean needsCallback() {  

  146.         return false;  

  147.     }  

  148.       

  149.     protected void updateTicket(final Ticket ticket) {  

  150.         addTicket(ticket);  

  151.     }  

  152.    

  153. }  


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

[html]    view plain   copy  

  1.     <!-- Ticket Registry -->  

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

  3.       

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

  5.  -->   

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

[html]    view plain   copy  

  1. <!-- TICKET REGISTRY CLEANER -->  

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

  3.     p:ticketRegistry-ref="ticketRegistry" />  

  4.   

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

  6.     p:targetObject-ref="ticketRegistryCleaner"  

  7.     p:targetMethod="clean" />  

  8.   

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

  10.     p:jobDetail-ref="jobDetailTicketRegistryCleaner"  

  11.     p:startDelay="20000"  

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


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


转 

mark

本文转载自:http://blog.csdn.net/roadmap001/article/details/8686301​

共有 人打赏支持
無雙
粉丝 2
博文 10
码字总数 3147
作品 0
宁波
程序员
CAS server和CAS Client 各类文章总结

CAS ( Central Authentication Service ) 是 Yale 大学发起的一个企业级的、开源的项目,旨在为 Web 应用系统提供一种可靠的单点登录解决方法(属于 Web SSO )。CAS集群部署首先需要考虑的...

afreon ⋅ 2016/11/24 ⋅ 0

cas单点登录集群如何优雅的退出

实现cas ticket基于redis的集群 目的 克服cas单点故障,将cas认证请求分发到多台cas服务器上,降低负载。实现思路: 采用统一的ticket存取策略,所有ticket的操作都从中央缓存redis中存取。采...

Heinrich_Chen ⋅ 2016/07/20 ⋅ 0

单点登录(cas)、缓存技术与负载均衡

提纲 动态缓存技术 集群与负载均衡 网罗天下实现策略 关键技术 动态缓存 基于动态缓存的电子商务优化 针对电子商务网站的特点和性能要求,在Web服务器前端设置动态缓存服务器,作为Web服务器...

soothwolf ⋅ 2013/09/29 ⋅ 1

CAS服务端redis集群搭建

注:cas4.0.x+Tomcat7+Jdk7+redis3.0 CAS中的票据默认是存储在TicketRegistry中的,若是想要实现CAS服务端的集群,首先要做的是将票据共享到缓存中。 1.实现AbstractDistributedTicketRegist...

战五渣 ⋅ 2016/10/15 ⋅ 1

开源 MIS 系统解决方案--jeeww

jeeww 是基于 spring+spring mvc+spring security+hibernate 为主的开源 MIS 系统解决方案,以 Maven 进行项目模块间的管理,便于扩展和管理,层次清晰,打造敏捷、清晰易用、松耦合、易扩展...

道在何方 ⋅ 2014/12/15 ⋅ 1

jeeww 1.0 完整带数据库可运行版发布

项目数据库文件更新,目前只有mysql,在/jeeww-web/src/main/webapp/assets/jeewwdb 20150117 1323.sql 1) jeeww 是基于 spring+spring mvc+hibernate 为主的开源 MIS 系统解决方案,以 Mave...

道在何方 ⋅ 2015/01/17 ⋅ 8

单点登录集群安装教程

在开发中的开源项目JeePlatform:https://github.com/u014427391/jeeplatform 欢迎start(s收藏),打算集成单点登录到自己的开源项目里,所以先搭建环境 【集群简介】 使用nginx作为负载均衡,...

Javahih ⋅ 2017/11/28 ⋅ 0

玩转Redis集群(下)

接上一篇《玩转Redis集群(上)》,我们来继续玩~ Redis集群操作实践 数据的分布性 从上面的操作,你可以看到,当存储某一个数据的时候,会分配一个slot,而这个slot从属于某一个Master,也就...

zfz_linux_boy ⋅ 2017/03/09 ⋅ 0

关于cas的企业开发的过程

cas是什么?本文这里不做解释自己百度。 关于cas企业开发的第一步:你需要利用cas做什么工作? 1 利用cas 做一个单纯的服务端。客户端调用即可。这个在网上的教程很多,只要明白了基本的都可...

天使broken ⋅ 2015/07/24 ⋅ 0

我对sso的使用和实现

我对sso的使用目前有三个阶段。 1.使用cas cas的好处自行搜索,缺点就是需要性能、维护、负载,如果cas宕机,从逻辑上来说就是所有的系统全部宕机了。 当然你可以维护集群,那就麻烦了。这个...

光石头 ⋅ 2014/02/14 ⋅ 6

没有更多内容

加载失败,请刷新页面

加载更多

下一页

CENTOS7防火墙命令记录

安装Firewall命令: yum install firewalld firewalld-config Firewall开启常见端口命令: firewall-cmd --zone=public --add-port=80/tcp --permanent firewall-cmd --zone=public --add-po......

cavion ⋅ 51分钟前 ⋅ 0

【C++】【STL】利用chromo来测量程序运行时间与日志时间打印精确到微秒

直接上代码吧,没啥好说的。头疼。 #include <iostream>#include <string>#include <ctime>#include <sstream>#include <iomanip>#include <thread>#include <chrono>using ......

muqiusangyang ⋅ 54分钟前 ⋅ 0

Mac环境下svn的使用

在Windows环境中,我们一般使用TortoiseSVN来搭建svn环境。在Mac环境下,由于Mac自带了svn的服务器端和客户端功能,所以我们可以在不装任何第三方软件的前提下使用svn功能,不过还需做一下简...

故久呵呵 ⋅ 今天 ⋅ 0

破解公司回应苹果“USB限制模式”:已攻破

本周四,苹果发表声明称 iOS 中加入了一项名为“USB 限制模式”的功能,可以防止 iPhone 在连接其他设备的时候被破解,并且强调这一功能并不是针对 FBI 等执法部门,为的是保护用户数据安全。...

六库科技 ⋅ 今天 ⋅ 0

MyBtais整合Spring Boot整合,TypeHandler对枚举类(enum)处理

概要 问题描述 我想用枚举类来表示用户当前状态,枚举类由 code 和 msg 组成,但我只想把 code 保存到数据库,查询处理,能知道用户当前状态,这应该怎么做呢?在 Spring 整合MyBatis 的时候...

Wenyi_Feng ⋅ 今天 ⋅ 0

synchronized与Lock的区别

# <center>王梦龙的读书笔记第一篇</center> ## <center>-synchronized与Lock的区别</centre> ###一、从使用场景来说 + synchronized 是能够注释代码块、类、方法但是它的加锁是和解锁使用一......

我不想加班 ⋅ 今天 ⋅ 0

VConsole的使用

手机端控制台打印输出,方便bug的排查。 首先需要引入vconsole.min.js 文件,然后在文件中创造实例。就能直接使用了。 var vConsole = new VConsole(); vConsole的文件地址...

大美琴 ⋅ 今天 ⋅ 0

Java NIO之字符集

1 字符集和编解码的概念 首先,解释一下什么是字符集。顾名思义,就是字符的集合。它的初衷是把现实世界的符号映射为计算机可以理解的字节。比如我创造一个字符集,叫做sex字符集,就包含两个...

士别三日 ⋅ 今天 ⋅ 0

Spring Bean基础

1、Bean之间引用 <!--如果Bean配置在同一个XML文件中,使用local引用--><ref bean="someBean"/><!--如果Bean配置在不同的XML文件中,使用ref引用--><ref local="someBean"/> 其实两种......

霍淇滨 ⋅ 今天 ⋅ 0

05、基于Consul+Upsync+Nginx实现动态负载均衡

1、Consul环境搭建 下载consul_0.7.5_linux_amd64.zip到/usr/local/src目录 cd /usr/local/srcwget https://releases.hashicorp.com/consul/0.7.5/consul_0.7.5_linux_amd64.zip 解压consu......

北岩 ⋅ 今天 ⋅ 0

没有更多内容

加载失败,请刷新页面

加载更多

下一页

返回顶部
顶部