CAS ( Central Authentication Service ) 是 Yale 大学发起的一个企业级的、开源的项目,旨在为 Web 应用系统提供一种可靠的单点登录解决方法(属于 Web SSO )。CAS集群部署首先需要考虑的是ticket票据统一存储的问题,以便于达到每个节点访问的一致性,官方虽然提供了基于memcached方式,但未提供基于Redis方式,项目中需要使用redis,因此仿照memcached方式,新建cas-server-integration-redis工程,来完成工作需求,下面本站素文宅www.yoodb.com就分享一下CAS集群部署基于Redis缓存配置,仅供大家参考学习。
主要特性,具体如下:
1)开源的、多协议的 SSO 解决方案; Protocols : Custom Protocol 、 CAS 、 OAuth 、 OpenID 、 RESTful API 、 SAML1.1 、 SAML2.0 等。
2)支持多种认证机制: Active Directory 、 JAAS 、 JDBC 、 LDAP 、 X.509 Certificates 等;
3)安全策略:使用票据( Ticket )来实现支持的认证协议;
4)支持授权:可以决定哪些服务可以请求和验证服务票据( Service Ticket );
5) 提 供高可用性:通过把认证过的状态数据存储在 TicketRegistry 组件中,这些组件有很多支持分布式环境的实现, 如: BerkleyDB 、 Default 、 EhcacheTicketRegistry 、 JDBCTicketRegistry 、 JBOSS TreeCache 、 JpaTicketRegistry 、 MemcacheTicketRegistry 等;
6)支持多种客户端: Java 、 .Net 、 PHP 、 Perl 、 Apache, uPortal 等。
1、构建cas-server-integration-redis工程
仿照cas-server-integration-memcached工程建立cas-server-integration-redis工程,pom.xml中添加redis的java客户端jar包,去掉memcached中需要的jar,最后依赖包如下:
<!-- ~ Licensed to Jasig under one or more contributor license ~ agreements. See the NOTICE file distributed with this work ~ for additional information regarding copyright ownership. ~ Jasig licenses this file to you under the Apache License, ~ Version 2.0 (the "License" ); you may not use this file ~ except in compliance with the License. You may obtain a ~ copy of the License at the following location: ~ ~ http: //www .apache.org /licenses/LICENSE-2 .0 ~ ~ Unless required by applicable law or agreed to in writing, ~ software distributed under the License is distributed on an ~ "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY ~ KIND, either express or implied. See the License for the ~ specific language governing permissions and limitations ~ under the License. --> <project xmlns= "http://maven.apache.org/POM/4.0.0" xmlns:xsi= "http://www.w3.org/2001/XMLSchema-instance" xsi:schemaLocation= "http://maven.apache.org/POM/4.0.0 http://maven.apache.org/maven-v4_0_0.xsd" > <parent> <groupId>org.jasig.cas< /groupId > <artifactId>cas-server< /artifactId > <version>3.5.2< /version > < /parent > <modelVersion>4.0.0< /modelVersion > <groupId>org.jasig.cas< /groupId > <artifactId>cas-server-integration-redis< /artifactId > <packaging>jar< /packaging > <name>Jasig CAS Redis Integration< /name > <dependencies> <dependency> <groupId>org.jasig.cas< /groupId > <artifactId>cas-server-core< /artifactId > <version>${project.version}< /version > < /dependency > <dependency> <groupId>redis.clients< /groupId > <artifactId>jedis< /artifactId > <version>2.8.1< /version > < /dependency > <!-- Test dependencies --> <dependency> <groupId>org.springframework.data< /groupId > <artifactId>spring-data-redis< /artifactId > <version>1.7.1.RELEASE< /version > < /dependency > <dependency> <groupId>org.mockito< /groupId > <artifactId>mockito-core< /artifactId > <version>1.9.0< /version > <scope> test < /scope > < /dependency > < /dependencies > < /project > |
仿照MemCacheTicketRegistry.java类,定义RedisTicketRegistry.java类,此类是核心,它实现了TicketRegistry接口,具体代码如下:
public class RedisTicketRegistry extends AbstractDistributedTicketRegistry{ @NotNull private final RedisTemplate<String,Object> reidsTemplate; /** * 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> reidsTemplate, int tgtTimeout, int stTimeout){ this .reidsTemplate=reidsTemplate; this .tgtTimeout=tgtTimeout; this .stTimeout=stTimeout; } @Override public void addTicket(Ticket ticket) { logger.debug( "Adding ticket {}" , ticket); try { reidsTemplate.opsForValue().set(ticket.getId(),ticket, getTimeout(ticket), TimeUnit.SECONDS); } catch ( final Exception e) { logger.error( "Failed adding {}" , ticket, e); } } @Override public Ticket getTicket(String ticketId) { try { final Ticket t = (Ticket) this .reidsTemplate.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) { logger.debug( "Deleting ticket {}" , ticketId); try { this .reidsTemplate.delete(ticketId); return true ; } catch ( final Exception e) { logger.error( "Failed deleting {}" , ticketId, e); } return false ; } @Override public Collection<Ticket> getTickets() { throw new UnsupportedOperationException( "GetTickets not supported." ); } @Override protected void updateTicket(Ticket ticket) { logger.debug( "Updating ticket {}" , ticket); try { this .reidsTemplate.delete(ticket.getId()); reidsTemplate.opsForValue().set(ticket.getId(),ticket, getTimeout(ticket), TimeUnit.SECONDS); } catch ( final Exception e) { logger.error( "Failed updating {}" , ticket, e); } } @Override protected boolean needsCallback() { // TODO Auto-generated method stub return true ; } 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" ); } } |
2、整合cas-server-webapp工程
修改cas-server-webapp工程中ticketRegistry.xml文件,替换掉DefaultTicketRegistry,同时注释掉ticketRegistryCleaner相关所有定义,具体如下:
<bean id = "ticketRegistry" class= "com.test.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 = "poolConfig" class= "redis.clients.jedis.JedisPoolConfig" > <property name= "maxIdle" value= "200" /> <property name= "testOnBorrow" value= "true" /> < /bean > <bean id = "connectionFactory" class= "org.springframework.data.redis.connection.jedis.JedisConnectionFactory" p:host-name= "127.0.0.1" p:port= "6379" p:pool-config-ref= "poolConfig" /> <!—host-name 服务端IP--> <bean id = "redisTemplate" class= "org.springframework.data.redis.core.RedisTemplate" p:connection-factory-ref= "connectionFactory" > < /bean > |
使用Redis作为ticket票据的存储,需要将原来的配置给注释掉否则启动时报错,具体如下:
<!-- <bean id = "ticketRegistry" class= "org.jasig.cas.ticket.registry.DefaultTicketRegistry" /> --> <!--Quartz --> <!-- TICKET REGISTRY CLEANER --> <!-- <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" /> --> |
在POM.xml中添加cas-server-integration-redis模块:
<dependency> <groupId>org.jasig.cas< /groupId > <artifactId>cas-server-integration-redis< /artifactId > <version>${project.version}< /version > <scope>compile< /scope > < /dependency > |
此时CAS配置完毕,启动所有相关服务器即可使用,下面说说tomcat session集群同步的问题
3、tomcat session集群同步
保证多个实例下,session中的状态以及票据存储状态,是一致的,通过网络上查找资料,实现tomcat session集群同步可以采用开源的tomcat-redis-session-manager,git hub地址为:https://github.com/jcoleman/tomcat-redis-session-manager,注意使用的JDK是JDK1.7,服务器使用的是tomcat7
1)拷贝编译打包之后的tomcat-redis-session-manager-VERSION.jar,jedis-2.7.2.jar,commons-pool2-2.2.jar到tomcat/lib目录下
2)修改Tomcat context.xml (or the context block of the server.xml if applicable.)
<Valve className= "com.orangefunction.tomcat.redissessions.RedisSessionHandlerValve" /> <Manager className= "com.orangefunction.tomcat.redissessions.RedisSessionManager" host= "127.0.0.1" port= "6379" database= "0" maxInactiveInterval= "1800" /> |
到此为止,CAS集群部署工作完毕,欢迎大家收藏本站,有什么疑难问题,尽可留言。