cas4.2.7 集群服务搭建
cas服务端集群,网上资料很多,无非就是session共享,ticket共享。 但是session共享是必须的吗?或者能实现集群吗?
实践:
1. ticket共享,直接上代码
package org.jasig.cas.ticket; import java.util.Collection;
import java.util.HashSet;
import java.util.Set;
import java.util.concurrent.TimeUnit; import org.jasig.cas.ticket.registry.AbstractDistributedTicketRegistry;
import org.springframework.beans.factory.DisposableBean;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.data.redis.core.StringRedisTemplate;
import org.springframework.stereotype.Component; /**
* @author zlx
* @Description: redis管理ticket
* @date 2018年4月9日 下午3:28:12
*/
@Component("redisTicketRegistry")
public class RedisTicketRegistry extends AbstractDistributedTicketRegistry implements DisposableBean {
/**管理ticket key,避免使用redis keys命令*/
private final String TICKET_KEY_MANAGER = "ticket_key_manager";
@Autowired
private RedisTemplate<String, Ticket> redisTemplate;
@Autowired
private StringRedisTemplate stringRedisTemplate;
//默认失效时间 /小时
private int timeout = 8; @Override
public void updateTicket(final Ticket ticket) {
logger.debug("Updating ticket {}", ticket);
try {
this.redisTemplate.boundValueOps(ticket.getId()).set(ticket);
this.redisTemplate.expire(ticket.getId(), timeout, TimeUnit.HOURS);
} catch (final Exception e) {
logger.error("Failed updating {}", ticket, e);
}
} @Override
public void addTicket(final Ticket ticket) {
logger.debug("Adding ticket {}", ticket);
try {
this.redisTemplate.boundValueOps(ticket.getId()).set(ticket);
this.redisTemplate.expire(ticket.getId(), timeout, TimeUnit.HOURS);
this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).add(ticket.getId());
} catch (final Exception e) {
logger.error("Failed adding {}", ticket, e);
}
} @Override
public int deleteTicket(final String ticketId) {
int count = 0;
logger.debug("Deleting ticket {}", ticketId);
try {
this.redisTemplate.delete(ticketId);
this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).remove(ticketId);
count++;
} catch (final Exception e) {
logger.error("Failed deleting {}", ticketId, e);
}
return count;
} @Override
public Ticket getTicket(final String ticketId) {
try {
final Ticket t = this.redisTemplate.boundValueOps(ticketId).get();
if (t != null) {
return getProxiedTicketInstance(t);
}
} catch (final Exception e) {
logger.error("Failed fetching {} ", ticketId, e);
}
return null;
} @Override
public boolean deleteSingleTicket(String ticketId) {
logger.debug("Deleting Single Ticket {}", ticketId);
try {
this.redisTemplate.delete(ticketId);
this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).remove(ticketId);
return true;
} catch (final Exception e) {
logger.error("Failed deleting {}", ticketId, e);
}
return false;
} @Override
public Collection<Ticket> getTickets() {
Set<Ticket> tickets = new HashSet<Ticket>(); Set<String> keys = this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).members();
for (String key : keys) {
Ticket ticket = this.redisTemplate.boundValueOps(key).get();
if (ticket == null) {
this.stringRedisTemplate.boundSetOps(TICKET_KEY_MANAGER).remove(key);
} else {
tickets.add(ticket);
}
}
return tickets;
} @Override
public void destroy() throws Exception {
// TODO Auto-generated method stub } @Override
protected boolean needsCallback() {
// TODO Auto-generated method stub
return false;
} }
deployerConfigContext.xml中变更:
<!-- <alias name="defaultTicketRegistry" alias="ticketRegistry" /> -->
<alias name="redisTicketRegistry" alias="ticketRegistry" />
ticket共享配好后,发布代码。 测试发现有时候cas集群有效。有时候报错。错误如下:
2018-05-14 16:48:11,841 ERROR [org.jasig.cas.util.WebflowCipherExecutor] - <Unable to correctly extract the Initialization Vector or ciphertext.>
org.apache.shiro.crypto.CryptoException: Unable to correctly extract the Initialization Vector or ciphertext.
at org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:378) ~[shiro-core-1.2.6.jar:1.2.6]
at org.jasig.cas.util.BinaryCipherExecutor.decode(BinaryCipherExecutor.java:102) ~[cas-server-core-util-4.2.7.jar:4.2.7]
at org.jasig.cas.util.BinaryCipherExecutor.decode(BinaryCipherExecutor.java:1) ~[cas-server-core-util-4.2.7.jar:4.2.7]
at org.jasig.cas.web.flow.CasWebflowCipherBean.decrypt(CasWebflowCipherBean.java:44) ~[cas-server-webapp-support-4.2.7.jar:4.2.7]
at org.jasig.spring.webflow.plugin.EncryptedTranscoder.decode(EncryptedTranscoder.java:105) ~[spring-webflow-client-repo-1.0.0.jar:1.0.0]
at org.jasig.spring.webflow.plugin.ClientFlowExecutionRepository.getFlowExecution(ClientFlowExecutionRepository.java:90) ~[spring-webflow-client-repo-1.0.0.jar:1.0.0]
at org.springframework.webflow.executor.FlowExecutorImpl.resumeExecution(FlowExecutorImpl.java:168) ~[spring-webflow-2.4.2.RELEASE.jar:2.4.2.RELEASE]
at org.springframework.webflow.mvc.servlet.FlowHandlerAdapter.handle(FlowHandlerAdapter.java:228) ~[spring-webflow-2.4.2.RELEASE.jar:2.4.2.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doDispatch(DispatcherServlet.java:961) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.servlet.DispatcherServlet.doService(DispatcherServlet.java:895) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.processRequest(FrameworkServlet.java:967) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.servlet.FrameworkServlet.doPost(FrameworkServlet.java:869) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:648) ~[servlet-api.jar:?]
at org.springframework.web.servlet.FrameworkServlet.service(FrameworkServlet.java:843) ~[spring-webmvc-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at javax.servlet.http.HttpServlet.service(HttpServlet.java:729) ~[servlet-api.jar:?]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:230) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
at org.apache.tomcat.websocket.server.WsFilter.doFilter(WsFilter.java:52) ~[tomcat-websocket.jar:8.5.0]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
at org.apereo.cas.security.ResponseHeadersEnforcementFilter.doFilter(ResponseHeadersEnforcementFilter.java:238) ~[cas-server-security-filter-2.0.6.jar:2.0.6]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
at org.apereo.cas.security.RequestParameterPolicyEnforcementFilter.doFilter(RequestParameterPolicyEnforcementFilter.java:261) ~[cas-server-security-filter-2.0.6.jar:2.0.6]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
at org.jasig.inspektr.common.web.ClientInfoThreadLocalFilter.doFilter(ClientInfoThreadLocalFilter.java:62) ~[inspektr-common-1.3.GA.jar:1.3.GA]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
at org.springframework.web.filter.CharacterEncodingFilter.doFilterInternal(CharacterEncodingFilter.java:121) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.filter.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:107) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
at org.springframework.session.web.http.SessionRepositoryFilter.doFilterInternal(SessionRepositoryFilter.java:164) ~[spring-session-1.2.2.RELEASE.jar:?]
at org.springframework.session.web.http.OncePerRequestFilter.doFilter(OncePerRequestFilter.java:80) ~[spring-session-1.2.2.RELEASE.jar:?]
at org.springframework.web.filter.DelegatingFilterProxy.invokeDelegate(DelegatingFilterProxy.java:346) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.springframework.web.filter.DelegatingFilterProxy.doFilter(DelegatingFilterProxy.java:262) ~[spring-web-4.2.8.RELEASE.jar:4.2.8.RELEASE]
at org.apache.catalina.core.ApplicationFilterChain.internalDoFilter(ApplicationFilterChain.java:192) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.ApplicationFilterChain.doFilter(ApplicationFilterChain.java:165) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.StandardWrapperValve.invoke(StandardWrapperValve.java:198) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.StandardContextValve.invoke(StandardContextValve.java:108) ~[catalina.jar:8.5.0]
at org.apache.catalina.authenticator.AuthenticatorBase.invoke(AuthenticatorBase.java:522) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.StandardHostValve.invoke(StandardHostValve.java:140) ~[catalina.jar:8.5.0]
at org.apache.catalina.valves.ErrorReportValve.invoke(ErrorReportValve.java:79) ~[catalina.jar:8.5.0]
at org.apache.catalina.valves.AbstractAccessLogValve.invoke(AbstractAccessLogValve.java:620) ~[catalina.jar:8.5.0]
at org.apache.catalina.core.StandardEngineValve.invoke(StandardEngineValve.java:87) ~[catalina.jar:8.5.0]
at org.apache.catalina.connector.CoyoteAdapter.service(CoyoteAdapter.java:343) ~[catalina.jar:8.5.0]
at org.apache.coyote.http11.Http11Processor.service(Http11Processor.java:1096) ~[tomcat-coyote.jar:8.5.0]
at org.apache.coyote.AbstractProcessorLight.process(AbstractProcessorLight.java:66) ~[tomcat-coyote.jar:8.5.0]
at org.apache.coyote.AbstractProtocol$ConnectionHandler.process(AbstractProtocol.java:760) ~[tomcat-coyote.jar:8.5.0]
at org.apache.tomcat.util.net.NioEndpoint$SocketProcessor.run(NioEndpoint.java:1480) ~[tomcat-coyote.jar:8.5.0]
at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1142) [?:1.8.0_77]
at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:617) [?:1.8.0_77]
at org.apache.tomcat.util.threads.TaskThread$WrappingRunnable.run(TaskThread.java:61) ~[tomcat-util.jar:8.5.0]
at java.lang.Thread.run(Thread.java:745) [?:1.8.0_77]
Caused by: java.lang.NullPointerException
at java.lang.System.arraycopy(Native Method) ~[?:1.8.0_77]
at org.apache.shiro.crypto.JcaCipherService.decrypt(JcaCipherService.java:370) ~[shiro-core-1.2.6.jar:1.2.6]
... 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[]:
@Override
public byte[] decrypt(final byte[] bytes) {
return webflowCipherExecutor.decode(bytes);
}
那么就自定义一个CipherExecutor,代码如下:
package org.jasig.cas.util; import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.stereotype.Component; /**
* No-Op cipher executor that does nothing for encryption/decryption.
* @author Misagh Moayyed
* @since 4.1
*/
@Component("noOpByteCipherExecutor")
public final class NoOpByteCipherExecutor extends AbstractCipherExecutor<byte[], byte[]> { private static final Logger LOGGER = LoggerFactory.getLogger(NoOpByteCipherExecutor.class); /**
* Instantiates a new No-Op cipher executor.
* Issues a warning on safety.
*/
public NoOpByteCipherExecutor() {
super(NoOpByteCipherExecutor.class.getName());
LOGGER.warn("[{}] does no encryption and may NOT be safe in a production environment. "
+ "Consider using other choices, such as [{}] that handle encryption, signing and verification of "
+ "all appropriate values.", this.getClass().getName(), BaseStringCipherExecutor.class.getName());
} @Override
public byte[] encode(final byte[] value) {
return value;
} @Override
public byte[] decode(final byte[] value) {
return value;
}
}
然后在cas-servlet.xml中配置:
<!-- 自定义CipherExecutor -->
<bean id="loginFlowCipherBean" class="org.jasig.cas.web.flow.CasWebflowCipherBean" >
<constructor-arg ref="noOpByteCipherExecutor" />
</bean>
要实现集群单点登录还需要在deployerConfigContext.xml增加如下配置:
<!-- 注入noOpCookieValueManager -->
<bean id="ticketGrantingTicketCookieGenerator" class="org.jasig.cas.web.support.TGCCookieRetrievingCookieGenerator">
<constructor-arg ref="noOpCookieValueManager" />
</bean>
至此实现了集群下的单点登录功能。
版权声明:本文为博主原创文章,转载需注明出处。http://www.cnblogs.com/bryanx/p/9044473.html
cas4.2.7 集群服务搭建的更多相关文章
- LVS负载均衡集群服务搭建详解(二)
lvs-nat模型构建 1.lvs-nat模型示意图 本次构建的lvs-nat模型的示意图如下,其中所有的服务器和测试客户端均使用VMware虚拟机模拟,所使用的CentOS 7 VS内核都支持ipv ...
- LVS负载均衡集群服务搭建详解(一)
LVS概述 1.LVS:Linux Virtual Server 四层交换(路由):根据请求报文的目标IP和目标PORT将其转发至后端主机集群中的某台服务器(根据调度算法): 不能够实现应用层的负载均 ...
- Nginx+Tomcat+Memcached负载均衡集群服务搭建
操作系统:CentOS6.5 本文档主要讲解,如何在CentOS6.5下搭建Nginx+Tomcat+Memcached负载均衡集群服务器,Nginx负责负载均衡,Tomcat负责实际服务,Memc ...
- solr5.3.1 集群服务搭建
转http://978538.blog.51cto.com/968538/1710442 一. 安装部署 zookeeper集群部署: 节点: 10.1.12.51:2181 node1 1 ...
- Redis6.0.6集群服务搭建
实现目标 一台主机上搭建3主3从高可用redis集群 环境 Linux :CentOS7 Redis : 6.0.6 准备工作 1.查看是否有安装wget命令,如果没有安装使用yum命令安装wgt命令 ...
- ZooKeeper一二事 - 搭建ZooKeeper伪分布式及正式集群 提供集群服务
集群真是好好玩,最近一段时间天天搞集群,redis缓存服务集群啦,solr搜索服务集群啦,,,巴拉巴拉 今天说说zookeeper,之前搭建了一个redis集群,用了6台机子,有些朋友电脑跑步起来,有 ...
- 使用Codis搭建redis集群服务
转(http://www.jianshu.com/p/f8e968e57863) 一. 应用场景 redis 作为数据结构存储引擎,有着很多优点 高性能单机引擎可以达到5-10W qps 数据结构全面 ...
- centos HA高可用集群 heartbeat搭建 heartbeat测试 主上停止heartbeat服务 测试脑裂 两边都禁用ping仲裁 第三十二节课
centos HA高可用集群 heartbeat搭建 heartbeat测试 主上停止heartbeat服务 测试脑裂 两边都禁用ping仲裁 第三十二节课 heartbeat是Linu ...
- CentOs7.3 搭建 SolrCloud 集群服务
一.概述 Lucene是一个Java语言编写的利用倒排原理实现的文本检索类库: Solr是以Lucene为基础实现的文本检索应用服务.Solr部署方式有单机方式.多机Master-Slaver方式.C ...
随机推荐
- [fw]谈EXPORT_SYMBOL使用
EXPORT_SYMBOL只出现在2.6内核中,在2.4内核默认的非static 函数和变量都会自动导入到kernel 空间的, 都不用EXPORT_SYMBOL() 做标记的.2.6就必须用EXPO ...
- CSS中表示颜色的4种方法
#1:直接用颜色名称 #2:十六进制数 #3:RGB整数设置颜色 0-255 #4:RGB百分数设置颜色0%-100%
- Nginx-LNMP架构搭建
目录 Nginx-LNMP架构搭建 LNMP架构概述 LNMP架构环境部署 部署LNMP 部署博客Wordpress 搭建知乎产品wecenter 搭建edusoho (修改域名及安装路径) 数据库拆 ...
- Linux拓展练习部分--输入输出 / find部分 /基础拓展2
目录 输入输出部分 find部分 基础阶段-拓展练习2 输入输出部分 1.输入时间命令"date"将当前系统时间输出到/data/1.txt [root@centos7 ~]# d ...
- Chocolatey Window系统下的软件管理工具
前言: 使用linux都喜欢使用yum ;apt-get来安装包,非常方便,那么windows也可以使用这样的方式. Chocolatey软件是Windows下的软件安装工具: 使用方法类似linux ...
- zabbix监控nginx status页面
在需要添加监控的nginx配置文件中添加下列配置 #zabbix监控nginx配置 location /nginx_status { stub_status on; access_log off; a ...
- JAVA 输入输出程序开发
参考: java中 静态方法和非静态方法的区别 字符流的输入和输出 java文件创建.删除.读取.写入操作大全 Java键盘输入并且写入文件 File类的isDiretory Java统计子串在字符串 ...
- MariaDB 选择查询
在本章中,我们将学习如何从表中选择数据. SELECT语句检索所选行. 它们可以包括UNION语句,排序子句,LIMIT子句,WHERE子句,GROUP BY ... HAVING子句和子查询. 查看 ...
- 阿里云Linux服务器购买、配置
购买.配置阿里云Linux服务器配置ftp发布网站全教程 http://blog.csdn.net/Jolesen/article/details/77505840
- sql 基础语法3:分组,聚合函数,having,联合查询,快速备份,内联函数
select * from Classinfo select * from StuInfo select * from CourseInfo select * from ScoreInfo --分组 ...