cas服务端集群,网上资料很多,无非就是session共享,ticket共享。 但是session共享是必须的吗?或者能实现集群吗?

实践:

1. ticket共享,直接上代码

  1. package org.jasig.cas.ticket;
  2.  
  3. import java.util.Collection;
  4. import java.util.HashSet;
  5. import java.util.Set;
  6. import java.util.concurrent.TimeUnit;
  7.  
  8. import org.jasig.cas.ticket.registry.AbstractDistributedTicketRegistry;
  9. import org.springframework.beans.factory.DisposableBean;
  10. import org.springframework.beans.factory.annotation.Autowired;
  11. import org.springframework.data.redis.core.RedisTemplate;
  12. import org.springframework.data.redis.core.StringRedisTemplate;
  13. import org.springframework.stereotype.Component;
  14.  
  15. /**
  16. * @author zlx
  17. * @Description: redis管理ticket
  18. * @date 2018年4月9日 下午3:28:12
  19. */
  20. @Component("redisTicketRegistry")
  21. public class RedisTicketRegistry extends AbstractDistributedTicketRegistry implements DisposableBean {
  22. /**管理ticket key,避免使用redis keys命令*/
  23. private final String TICKET_KEY_MANAGER = "ticket_key_manager";
  24. @Autowired
  25. private RedisTemplate<String, Ticket> redisTemplate;
  26. @Autowired
  27. private StringRedisTemplate stringRedisTemplate;
  28. //默认失效时间 /小时
  29. private int timeout = 8;
  30.  
  31. @Override
  32. public void updateTicket(final Ticket ticket) {
  33. logger.debug("Updating ticket {}", ticket);
  34. try {
  35. this.redisTemplate.boundValueOps(ticket.getId()).set(ticket);
  36. this.redisTemplate.expire(ticket.getId(), timeout, TimeUnit.HOURS);
  37. } catch (final Exception e) {
  38. logger.error("Failed updating {}", ticket, e);
  39. }
  40. }
  41.  
  42. @Override
  43. public void addTicket(final Ticket ticket) {
  44. logger.debug("Adding ticket {}", ticket);
  45. try {
  46. this.redisTemplate.boundValueOps(ticket.getId()).set(ticket);
  47. this.redisTemplate.expire(ticket.getId(), timeout, TimeUnit.HOURS);
  48. this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).add(ticket.getId());
  49. } catch (final Exception e) {
  50. logger.error("Failed adding {}", ticket, e);
  51. }
  52. }
  53.  
  54. @Override
  55. public int deleteTicket(final String ticketId) {
  56. int count = 0;
  57. logger.debug("Deleting ticket {}", ticketId);
  58. try {
  59. this.redisTemplate.delete(ticketId);
  60. this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).remove(ticketId);
  61. count++;
  62. } catch (final Exception e) {
  63. logger.error("Failed deleting {}", ticketId, e);
  64. }
  65. return count;
  66. }
  67.  
  68. @Override
  69. public Ticket getTicket(final String ticketId) {
  70. try {
  71. final Ticket t = this.redisTemplate.boundValueOps(ticketId).get();
  72. if (t != null) {
  73. return getProxiedTicketInstance(t);
  74. }
  75. } catch (final Exception e) {
  76. logger.error("Failed fetching {} ", ticketId, e);
  77. }
  78. return null;
  79. }
  80.  
  81. @Override
  82. public boolean deleteSingleTicket(String ticketId) {
  83. logger.debug("Deleting Single Ticket {}", ticketId);
  84. try {
  85. this.redisTemplate.delete(ticketId);
  86. this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).remove(ticketId);
  87. return true;
  88. } catch (final Exception e) {
  89. logger.error("Failed deleting {}", ticketId, e);
  90. }
  91. return false;
  92. }
  93.  
  94. @Override
  95. public Collection<Ticket> getTickets() {
  96. Set<Ticket> tickets = new HashSet<Ticket>();
  97.  
  98. Set<String> keys = this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).members();
  99. for (String key : keys) {
  100. Ticket ticket = this.redisTemplate.boundValueOps(key).get();
  101. if (ticket == null) {
  102. this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).remove(key);
  103. } else {
  104. tickets.add(ticket);
  105. }
  106. }
  107. return tickets;
  108. }
  109.  
  110. @Override
  111. public void destroy() throws Exception {
  112. // TODO Auto-generated method stub
  113.  
  114. }
  115.  
  116. @Override
  117. protected boolean needsCallback() {
  118. // TODO Auto-generated method stub
  119. return false;
  120. }
  121.  
  122. }

deployerConfigContext.xml中变更:

  1. <!-- <alias name="defaultTicketRegistry" alias="ticketRegistry" /> -->
  2. <alias name="redisTicketRegistry" alias="ticketRegistry" />

ticket共享配好后,发布代码。 测试发现有时候cas集群有效。有时候报错。错误如下:

  1. 2018-05-14 16:48:11,841 ERROR [org.jasig.cas.util.WebflowCipherExecutor] - <Unable to correctly extract the Initialization Vector or ciphertext.>
  2. org.apache.shiro.crypto.CryptoException: Unable to correctly extract the Initialization Vector or ciphertext.
  3. at org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:378) ~[shiro-core-1.2.6.jar:1.2.6]
  4. at org.jasig.cas.util.BinaryCipherExecutor.decode(BinaryCipherExecutor.java:102) ~[cas-server-core-util-4.2.7.jar:4.2.7]
  5. at org.jasig.cas.util.BinaryCipherExecutor.decode(BinaryCipherExecutor.java:1) ~[cas-server-core-util-4.2.7.jar:4.2.7]
  6. at org.jasig.cas.web.flow.CasWebflowCipherBean.decrypt(CasWebflowCipherBean.java:44) ~[cas-server-webapp-support-4.2.7.jar:4.2.7]
  7. at org.jasig.spring.webflow.plugin.EncryptedTranscoder.decode(EncryptedTranscoder.java:105) ~[spring-webflow-client-repo-1.0.0.jar:1.0.0]
  8. at org.jasig.spring.webflow.plugin.ClientFlowExecutionRepository.getFlowExecution(ClientFlowExecutionRepository.java:90) ~[spring-webflow-client-repo-1.0.0.jar:1.0.0]
  9. at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:168) ~[spring-webflow-2.4.2.RELEASE.jar:2.4.2.RELEASE]
  10. at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:228) ~[spring-webflow-2.4.2.RELEASE.jar:2.4.2.RELEASE]
  11. at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  12. at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  13. at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  14. at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  15. at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) ~[servlet-api.jar:?]
  16. at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  17. at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[servlet-api.jar:?]
  18. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[catalina.jar:8.5.0]
  19. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
  20. at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-websocket.jar:8.5.0]
  21. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
  22. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
  23. at org.apereo.cas.security.ResponseHeadersEnforcementFilter.doFilter(ResponseHeadersEnforcementFilter.java:238) ~[cas-server-security-filter-2.0.6.jar:2.0.6]
  24. at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  25. at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  26. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
  27. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
  28. at org.apereo.cas.security.RequestParameterPolicyEnforcementFilter.doFilter(RequestParameterPolicyEnforcementFilter.java:261) ~[cas-server-security-filter-2.0.6.jar:2.0.6]
  29. at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  30. at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  31. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
  32. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
  33. at org.jasig.inspektr.common.web.ClientInfoThreadLocalFilter.doFilter(ClientInfoThreadLocalFilter.java:62) ~[inspektr-common-1.3.GA.jar:1.3.GA]
  34. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
  35. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
  36. at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  37. at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  38. at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  39. at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  40. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
  41. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
  42. at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:164) ~[spring-session-1.2.2.RELEASE.jar:?]
  43. at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80) ~[spring-session-1.2.2.RELEASE.jar:?]
  44. at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  45. at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
  46. at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
  47. at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
  48. at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[catalina.jar:8.5.0]
  49. at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108) ~[catalina.jar:8.5.0]
  50. at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:522) ~[catalina.jar:8.5.0]
  51. at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) ~[catalina.jar:8.5.0]
  52. at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) ~[catalina.jar:8.5.0]
  53. at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620) ~[catalina.jar:8.5.0]
  54. at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) ~[catalina.jar:8.5.0]
  55. at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[catalina.jar:8.5.0]
  56. at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1096) ~[tomcat-coyote.jar:8.5.0]
  57. at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-coyote.jar:8.5.0]
  58. at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:760) ~[tomcat-coyote.jar:8.5.0]
  59. at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1480) ~[tomcat-coyote.jar:8.5.0]
  60. at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_77]
  61. at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_77]
  62. at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-util.jar:8.5.0]
  63. at java.lang.Thread.run(Thread.java:745) [?:1.8.0_77]
  64. Caused by: java.lang.NullPointerException
  65. at java.lang.System.arraycopy(Native Method) ~[?:1.8.0_77]
  66. at org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:370) ~[shiro-core-1.2.6.jar:1.2.6]
  67. ... 60 more

查资料都说要用tomcat redis session manager实现集群tomcat的session共享

那就根据资料配置好tomcat redis session manager,使用压力测试(集群切换分发更频繁)还是一样一部分成功一部分失败。也使用spring redis session试过了还是一样。

后来发现了一篇文章:https://blog.csdn.net/eguid_1/article/details/51444009

仔细分析了下spring web flow的源码,确定了问题就是出在webflow流程控制上,使用组播方式实现session复制也无济于事(也配过了,确实没有效果),修改spring webflow的源码难度太大,绕过webflow登录流程代码改动太大。

为了寻找到更好的解决方案,继续分析、跟踪cas源码,从最底层错误开始分析

1. JcaCipherService.java:370

2. BinaryCipherExecutor.java:102

3. CasWebflowCipherBean.java:44

这一步发现调用的CipherExecutor是可以选择的,默认使用的为BinaryCipherExecutor。既然BinaryCipherExecutor里报错那就换NoOpCipherExecutor试试看。因为NoOpCipherExecutor的encode和decode方法的参数和返回值是String类型

而CasWebflowCipherBean调用时传的是byte[]:

  1. @Override
  2. public byte[] decrypt(final byte[] bytes) {
  3. return webflowCipherExecutor.decode(bytes);
  4. }

那么就自定义一个CipherExecutor,代码如下:

  1. package org.jasig.cas.util;
  2.  
  3. import org.slf4j.Logger;
  4. import org.slf4j.LoggerFactory;
  5. import org.springframework.stereotype.Component;
  6.  
  7. /**
  8. * No-Op cipher executor that does nothing for encryption/decryption.
  9. * @author Misagh Moayyed
  10. * @since 4.1
  11. */
  12. @Component("noOpByteCipherExecutor")
  13. public final class NoOpByteCipherExecutor extends AbstractCipherExecutor<byte[], byte[]> {
  14.  
  15. private static final Logger LOGGER = LoggerFactory.getLogger(NoOpByteCipherExecutor.class);
  16.  
  17. /**
  18. * Instantiates a new No-Op cipher executor.
  19. * Issues a warning on safety.
  20. */
  21. public NoOpByteCipherExecutor() {
  22. super(NoOpByteCipherExecutor.class.getName());
  23. LOGGER.warn("[{}] does no encryption and may NOT be safe in a production environment. "
  24. + "Consider using other choices, such as [{}] that handle encryption, signing and verification of "
  25. + "all appropriate values.", this.getClass().getName(), BaseStringCipherExecutor.class.getName());
  26. }
  27.  
  28. @Override
  29. public byte[] encode(final byte[] value) {
  30. return value;
  31. }
  32.  
  33. @Override
  34. public byte[] decode(final byte[] value) {
  35. return value;
  36. }
  37. }

然后在cas-servlet.xml中配置:

  1. <!-- 自定义CipherExecutor -->
  2. <bean id="loginFlowCipherBean" class="org.jasig.cas.web.flow.CasWebflowCipherBean" >
  3.   <constructor-arg ref="noOpByteCipherExecutor" />
    </bean>

要实现集群单点登录还需要在deployerConfigContext.xml增加如下配置:

  1. <!-- 注入noOpCookieValueManager -->
  2. <bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.TGCCookieRetrievingCookieGenerator">
  3. <constructor-arg ref="noOpCookieValueManager" />
  4. </bean>

至此实现了集群下的单点登录功能。

版权声明:本文为博主原创文章,转载需注明出处。http://www.cnblogs.com/bryanx/p/9044473.html

cas4.2.7 集群服务搭建的更多相关文章

  1. LVS负载均衡集群服务搭建详解(二)

    lvs-nat模型构建 1.lvs-nat模型示意图 本次构建的lvs-nat模型的示意图如下,其中所有的服务器和测试客户端均使用VMware虚拟机模拟,所使用的CentOS 7 VS内核都支持ipv ...

  2. LVS负载均衡集群服务搭建详解(一)

    LVS概述 1.LVS:Linux Virtual Server 四层交换(路由):根据请求报文的目标IP和目标PORT将其转发至后端主机集群中的某台服务器(根据调度算法): 不能够实现应用层的负载均 ...

  3. Nginx+Tomcat+Memcached负载均衡集群服务搭建

    操作系统:CentOS6.5  本文档主要讲解,如何在CentOS6.5下搭建Nginx+Tomcat+Memcached负载均衡集群服务器,Nginx负责负载均衡,Tomcat负责实际服务,Memc ...

  4. solr5.3.1 集群服务搭建

    转http://978538.blog.51cto.com/968538/1710442 一. 安装部署 zookeeper集群部署: 节点: 10.1.12.51:2181      node1 1 ...

  5. Redis6.0.6集群服务搭建

    实现目标 一台主机上搭建3主3从高可用redis集群 环境 Linux :CentOS7 Redis : 6.0.6 准备工作 1.查看是否有安装wget命令,如果没有安装使用yum命令安装wgt命令 ...

  6. ZooKeeper一二事 - 搭建ZooKeeper伪分布式及正式集群 提供集群服务

    集群真是好好玩,最近一段时间天天搞集群,redis缓存服务集群啦,solr搜索服务集群啦,,,巴拉巴拉 今天说说zookeeper,之前搭建了一个redis集群,用了6台机子,有些朋友电脑跑步起来,有 ...

  7. 使用Codis搭建redis集群服务

    转(http://www.jianshu.com/p/f8e968e57863) 一. 应用场景 redis 作为数据结构存储引擎,有着很多优点 高性能单机引擎可以达到5-10W qps 数据结构全面 ...

  8. centos HA高可用集群 heartbeat搭建 heartbeat测试 主上停止heartbeat服务 测试脑裂 两边都禁用ping仲裁 第三十二节课

    centos   HA高可用集群  heartbeat搭建 heartbeat测试  主上停止heartbeat服务  测试脑裂  两边都禁用ping仲裁  第三十二节课 heartbeat是Linu ...

  9. CentOs7.3 搭建 SolrCloud 集群服务

    一.概述 Lucene是一个Java语言编写的利用倒排原理实现的文本检索类库: Solr是以Lucene为基础实现的文本检索应用服务.Solr部署方式有单机方式.多机Master-Slaver方式.C ...

随机推荐

  1. money (dp)

    牛客网暑假训练第二场D题: 链接:https://www.nowcoder.com/acm/contest/140/D来源:牛客网 题目描述 White Cloud has built n store ...

  2. data-*存数据,拿出ul li中的数据

    <ul class="questions"> <li> <div class="question">1.您的年龄是?< ...

  3. 使用Python+Qt时解决QTreeWidget中的内容超出边界后自动隐藏的问题

    问题: 默认情况下,内容超出边界后会自动省略,以...代替,而且无法出现水平滚动条 解决方法: 把VerticalScrollBar和HorizontalScrollBar的值都设为ScrollBar ...

  4. SQL join的示意图

    SQL join 用于把来自两个或多个表的行结合起来. 下图展示了 LEFT JOIN.RIGHT JOIN.INNER JOIN.OUTER JOIN 相关的 7 种用法. 注意JOIN要和ON相连 ...

  5. spring boot poi 导出Excel

    public class ExcelData implements Serializable { private static final long serialVersionUID = 444401 ...

  6. PHP实现笛卡尔积算法

    概念 在数学中,两个集合X和Y的笛卡儿积(Cartesian product),又称直积,表示为 X × Y.设A.B是任意两个集合,在集合A中任意取一个元素x,在集合B中任意取一个元素y,组成一个有 ...

  7. laravel 跨域解决方案

    我们在用 laravel 进行开发的时候,特别是前后端完全分离的时候,由于前端项目运行在自己机器的指定端口(也可能是其他人的机器) , 例如 localhost:8000 , 而 laravel 程序 ...

  8. MySQL解决插入数据乱码问题

    首先配置 my.ini 如果没有将原来的 my-default.ini 备份出一个 修改my.ini [1]在[client]节点下添加 (这个如果是另一种character_set_server=u ...

  9. List Comprehension ()(二)

    在list comprehension中加入if条件判断: >>> lines = [line.rstrip() for line in open('script2.py') if ...

  10. cocos2D-X c++ call java

    { //https://blog.csdn.net/yuechuzhao/article/details/9283847 }