文档章节

cas3.5.2集群化部署及定制开发

j
 janwenjohn
发布于 2015/07/21 13:39
字数 1516
阅读 59
收藏 2

本文转自我的博客,转载请申明地址:http://www.heartlifes.com/archives/14/

集群化方案:##

1.tomcat集群共享session 2.持久化票根st及tgt 3.持久化service 4.修改ServiceManager,从内存共享改为redis共享

tomcat集群共享session###

之所以要共享session,是因为cas使用了spring-webflow,而webflow使用session存储中间变量,如果不共享session,会直接导致登录流程因为缺少中间变量而失败,具体表现为输入正确用户名密码后,界面刷新重新进入登录界面。

session共享在tomcat中有三种方案可供选择,分别是:1.tomcat原始集群共享。2.redis session持久化共享。3.memcache session持久化共享。

这里我选用了tomcat原始的集群共享,原因是redis session持久化实验失败,session是成功持久化到redis中了,但是登录流程还是失败,memcache由于没有环境,没有试验。

配制tomcat集群####

1.在server.xml的Engine元素下加入以下配制

    <Cluster className="org.apache.catalina.ha.tcp.SimpleTcpCluster">
      <Manager className="org.apache.catalina.ha.session.DeltaManager"
             expireSessionsOnShutdown="false"
             notifyListenersOnReplication="true"/>
      <Channel className="org.apache.catalina.tribes.group.GroupChannel">
        <Membership
            className="org.apache.catalina.tribes.membership.McastService"
            address="228.0.0.4"
            port="45564"
            frequency="500"
            dropTime="3000"
            mcastTTL="1"/>
        <Receiver
            className="org.apache.catalina.tribes.transport.nio.NioReceiver"
            address="xxx"
            port="4001"
            autoBind="0"
            selectorTimeout="100"
            maxThreads="6"/>
        <Sender className="org.apache.catalina.tribes.transport.ReplicationTransmitter">
          <Transport className="org.apache.catalina.tribes.transport.nio.PooledParallelSender"/>
        </Sender>
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.TcpFailureDetector"/>
        <Interceptor className="org.apache.catalina.tribes.group.interceptors.MessageDispatch15Interceptor"/>
      </Channel>
      <Valve className="org.apache.catalina.ha.tcp.ReplicationValve"
           filter=".*\.gif;.*\.js;.*\.jpg;.*\.htm;.*\.html;.*\.txt;"/>
      <ClusterListener className="org.apache.catalina.ha.session.ClusterSessionListener"/>
    </Cluster>

上面的address="xxx",替换成你自己的服务器ip地址

2.在工程web.xml的开头加入配置项

<distributable />

持久化票根####

票根的持久化,cas默认就提供了支持,我们所要做的就是把相应的持久化类使用起来,在配置文件中替换掉原来的内存存储类。 1.pom中增加以下依赖:

<dependency>
	<groupId>mysql</groupId>
	<artifactId>mysql-connector-java</artifactId>
	<version>5.1.18</version>
</dependency>
<dependency>
	<groupId>redis.clients</groupId>
	<artifactId>jedis</artifactId>
	<version>2.6.2</version>
	<type>jar</type>
	<scope>compile</scope>
</dependency>
<dependency>
	<groupId>org.springframework.data</groupId>
	<artifactId>spring-data-redis</artifactId>
	<version>1.5.0.RELEASE</version>
</dependency>
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-core</artifactId>
	<version>4.1.0.Final</version>
</dependency>
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-entitymanager</artifactId>
	<version>4.1.0.Final</version>
</dependency>
<dependency>
	<groupId>org.hibernate</groupId>
	<artifactId>hibernate-validator</artifactId>
	<scope>runtime</scope>
	<version>4.2.0.Final</version>
</dependency>
<dependency>
	<groupId>com.alibaba</groupId>
	<artifactId>druid</artifactId>
	<version>1.0.1</version>
</dependency>

以上依赖包括mysql驱动,hibernate相关包,druid数据连接池及redis驱动(redis用于后面service持久化)

2.applicationContext.xml文件修改 增加以下配置项:

<tx:annotation-driven transaction-manager="transactionManager" />

<context:component-scan base-package="com" />

<bean id="dataSource" class="com.alibaba.druid.pool.DruidDataSource" init-method="init" destroy-method="close">
    <!-- 数据源驱动类可不写,Druid默认会自动根据URL识别DriverClass -->
    <property name="driverClassName" value="${jdbc.driver}" />
    <!-- 基本属性 url、user、password -->
    <property name="url" value="${jdbc.url}" />
    <property name="username" value="${jdbc.username}" />
    <property name="password" value="${jdbc.password}" />
    <!-- 配置初始化大小、最小、最大 -->
    <property name="initialSize" value="${jdbc.pool.minIdle}" />
    <property name="minIdle" value="${jdbc.pool.minIdle}" />
    <property name="maxActive" value="${jdbc.pool.maxActive}" />
    <!-- 配置获取连接等待超时的时间 -->
    <property name="maxWait" value="30000" />
    <!-- 配置间隔多久才进行一次检测,检测需要关闭的空闲连接,单位是毫秒 -->
    <property name="timeBetweenEvictionRunsMillis" value="30000" />
    <!-- 配置一个连接在池中最小生存的时间,单位是毫秒 -->
    <property name="minEvictableIdleTimeMillis" value="90000" />
    <property name="validationQuery" value="SELECT 'x'" />
    <property name="testWhileIdle" value="true" />
    <property name="testOnBorrow" value="false" />
    <property name="testOnReturn" value="false" />
</bean>

<bean id="entityManagerFactory" class="org.springframework.orm.jpa.LocalContainerEntityManagerFactoryBean"    p:dataSource-ref="dataSource" p:jpaVendorAdapter-ref="jpaVendorAdapter">
    <property name="jpaProperties">
        <props>
	    <prop key="hibernate.dialect">${database.dialect}</prop>
	    <prop key="hibernate.hbm2ddl.auto">update</prop>
	    <prop key="hibernate.jdbc.batch_size">${database.batchSize}</prop>
	</props>
    </property>
</bean>

<bean id="jpaVendorAdapter" class="org.springframework.orm.jpa.vendor.HibernateJpaVendorAdapter" p:generateDdl="true" p:showSql="true" />

<bean id="transactionManager" class="org.springframework.orm.jpa.JpaTransactionManager" p:entityManagerFactory-ref="entityManagerFactory" />

<bean class="org.springframework.orm.jpa.support.PersistenceAnnotationBeanPostProcessor" />

2.ticketRegistry.xml文件修改 查找ticketRegistry,修改原bean声明如下:

<bean id="ticketRegistry" class="org.jasig.cas.ticket.registry.JpaTicketRegistry" />

持久化service####

1.deployerConfigContext.xml文件修改 查找serviceRegistryDao,修改bean声明

<bean id="serviceRegistryDao" class="org.jasig.cas.services.JpaServiceRegistryDaoImpl"		p:entityManagerFactory-ref="entityManagerFactory" />

修改ServiceManger####

cas自带的DefaultServicesManagerImpl的集群模式,是通过直接将所有的service存在内存的一个set中,然后通过quartz,每两分钟reload一把全量service,这种2分钟同步一次service的集群模式,显然不能正式上线使用,这里我们通过自己实现ServiceManager,采用redis,对所有service进行统一管理。

1.增加RedisServicesManagerImpl类:

public class RedisServicesManagerImpl implements ServicesManager {

	private final Logger log = LoggerFactory.getLogger(getClass());

	private final static String SPLIT = ",";

	private final static String REDIS_KEY = "registedService";

	@NotNull
	private ServiceRegistryDao serviceRegistryDao;

	private RegisteredService disabledRegisteredService;

	private RedisTemplate<String, RegisteredService> redisTemplate;

	private RegexRegisteredService defaultService = new RegexRegisteredService();
	
	public RedisServicesManagerImpl(final ServiceRegistryDao serviceRegistryDao,			final RedisTemplate<String, RegisteredService> redisTemplate) {
		this.serviceRegistryDao = serviceRegistryDao;
		this.disabledRegisteredService = constructDefaultRegisteredService(new ArrayList<String>());
		this.redisTemplate = redisTemplate;

		constructDefaultService();
	}

	@Transactional(readOnly = false)
	@Audit(action = "DELETE_SERVICE", actionResolverName = "DELETE_SERVICE_ACTION_RESOLVER", resourceResolverName = "DELETE_SERVICE_RESOURCE_RESOLVER")
	public synchronized RegisteredService delete(final long id) {
		final RegisteredService r = findServiceBy(id);
		if (r == null) {
			return null;
		}
		log.info("delete service by id..." + r.getServiceId() + "..."
				+ r.getId());
		this.serviceRegistryDao.delete(r);
		String key = r.getId() + SPLIT + r.getServiceId();
		// redisTemplate.opsForValue().getOperations().delete(key);
		redisTemplate.opsForHash().delete(REDIS_KEY, key);
		return r;
	}

	public RegisteredService findServiceBy(final Service service) {
		if (service != null) {
			log.info("find service by service..." + service.getId() + "..."
					+ service.getClass());
		}
		Collection<RegisteredService> c = getAllServices();
		if (c.isEmpty()) {
			log.info("find service by service...service is blank");
			return this.disabledRegisteredService;
		}

		for (final RegisteredService r : c) {
			if (r.matches(service)) {
				log.info("find service by service...service is a match...in service..."
						+ service.getId()
						+ "...with redis..."
						+ r.getServiceId());
				return r;
			}
		}
		log.info("find service by service...service not match");
		return null;
	}

	public RegisteredService findServiceBy(final long id) {
		log.info("find service by id..." + id);
		Map<Object, Object> map = redisTemplate.opsForHash().entries(REDIS_KEY);
		Set<Entry<Object, Object>> set = map.entrySet();
		Iterator<Entry<Object, Object>> it = set.iterator();
		while (it.hasNext()) {
			Entry<Object, Object> entry = it.next();
			String key = entry.getKey().toString();
			RegisteredService value = (RegisteredService) entry.getKey();
			log.info("find service by id...service in redis..." + key);
			if (String.valueOf(id).equals(key.split(SPLIT)[0])) {
				log.info("find service by id...match..." + key);
				try {
					return (RegisteredService) value.clone();
				} catch (final CloneNotSupportedException e) {
					return value;
				}
			}
		}
		return null;
	}

	public Collection<RegisteredService> getAllServices() {
		log.info("get all services...");
		Set<RegisteredService> services = new TreeSet<RegisteredService>();
		Map<Object, Object> map = redisTemplate.opsForHash().entries(REDIS_KEY);
		Set<Entry<Object, Object>> set = map.entrySet();
		Iterator<Entry<Object, Object>> it = set.iterator();
		while (it.hasNext()) {
			Entry<Object, Object> entry = it.next();

			log.info("get all services...service in redis..." + entry.getKey()
					+ "..." + entry.getValue().getClass());

			String key = entry.getKey().toString();
			if (entry.getValue() instanceof RegisteredService) {
				RegisteredService value = (RegisteredService) entry.getValue();
				log.info("get all services...service in redis..." + key);
				services.add(value);
			}
		}
		if (!services.contains(defaultService)) {
			services.add(defaultService);
		}
		return services;
	}

	public boolean matchesExistingService(final Service service) {
		return findServiceBy(service) != null;
	}

	@Transactional(readOnly = false)
	@Audit(action = "SAVE_SERVICE", actionResolverName = "SAVE_SERVICE_ACTION_RESOLVER", resourceResolverName = "SAVE_SERVICE_RESOURCE_RESOLVER")
	public synchronized RegisteredService save(
			final RegisteredService registeredService) {
		log.info("save service..." + registeredService.getServiceId());
		final RegisteredService r = this.serviceRegistryDao
				.save(registeredService);

		String key = registeredService.getId() + SPLIT
				+ registeredService.getServiceId();
		log.info("save service in redis..." + key);
		// redisTemplate.opsForValue().set(key, registeredService);
		redisTemplate.opsForHash().put(REDIS_KEY, key, registeredService);
		return r;
	}

	private RegisteredService constructDefaultRegisteredService(
			final List<String> attributes) {
		final RegisteredServiceImpl r = new RegisteredServiceImpl();
		r.setAllowedToProxy(true);
		r.setAnonymousAccess(false);
		r.setEnabled(true);
		r.setSsoEnabled(true);
		r.setAllowedAttributes(attributes);

		if (attributes == null || attributes.isEmpty()) {
			r.setIgnoreAttributes(true);
		}

		return r;
	}

	private void constructDefaultService() {
		defaultService.setId(0);
		defaultService.setName("HTTP and IMAP");
		defaultService.setDescription("Allows HTTP(S) and IMAP(S) protocols");
		defaultService.setServiceId("^(https?|imaps?)://.*");
		defaultService.setEvaluationOrder(10000001);
	}

}

2.applicationContext.xml文件修改 增加以下配置项:

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
    <property name="maxTotal" value="${redis.pool.maxActive}" />
    <property name="maxIdle" value="${redis.pool.maxIdle}" />
    <property name="maxWaitMillis" value="${redis.pool.maxWait}" />
    <property name="testOnBorrow" value="${redis.pool.testOnBorrow}" />
</bean>

<bean id="jedisConnectionFactory" class="org.springframework.data.redis.connection.jedis.JedisConnectionFactory">
    <property name="hostName" value="${redis.hostname}" />
    <property name="port" value="${redis.port}" />
    <property name="password" value="${redis.password}" />
    <property name="poolConfig" ref="jedisPoolConfig" />
</bean>

<bean id="redisTemplate" class="org.springframework.data.redis.core.RedisTemplate">
    <property name="connectionFactory" ref="jedisConnectionFactory" />
</bean>

修改以下配置项:

<bean id="servicesManager" class="com.wondersgroup.cas.services.RedisServicesManagerImpl">
	<constructor-arg index="0" ref="serviceRegistryDao" />
	<constructor-arg index="1" ref="redisTemplate" />
</bean>

© 著作权归作者所有

共有 人打赏支持
j
粉丝 0
博文 10
码字总数 5840
作品 0
闸北
私信 提问
CAS server和CAS Client 各类文章总结

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

afreon
2016/11/24
22
0
prometheus-operator架构部署( prometheus-server, pushgateway, grafana, alertmanater,servicemonitor...)

版权声明:本文为博主原创文章,转载请注明来源。开发合作联系luanpenguestc@sina.com https://blog.csdn.net/luanpeng825485697/article/details/83755430 github官网:https://github.com/c...

数据架构师
2018/11/07
0
0
Prometheus Operator 架构 - 每天5分钟玩转 Docker 容器技术(178)

本节讨论 Prometheus Operator 的架构。 因为 Prometheus Operator 是基于 Prometheus 的,我们需要先了解一下 Prometheus。 Prometheus 架构 Prometheus 是一个非常优秀的监控工具。准确的说...

cloudman6
2018/06/07
0
0
【360开源】Wayne:企业级可视化多集群Kubernetes一站式管理平台

宣言 Wayne是由360搜索云平台团队开发的,一个通用的、基于Web的Kubernetes多集群一站式可视化管理平台。内置了丰富多样的功能,满足企业的通用需求,同时插件化的方式可以方便集成定制化功能...

ZVAyIVqt0UFji
2018/11/19
0
0
6月9日上海 华东运维技术大会:演讲主题、演讲嘉宾等信息

会议名称:华东运维技术大会 参会形式:免费报名制(注释:须事先报名,场地有限) 会议定位:企业运维技术的最佳实践 会议主题:运维自动化、Web服务器的优化与架构、云计算、虚拟化技术 会...

金官丁
2012/05/19
2.5K
11

没有更多内容

加载失败,请刷新页面

加载更多

dockerfile 镜像构建(1)

通用dockerfile 利用已经编译好的.jar 来构建镜像。要构建的目录如下: [root@iZuf61quxhnlk9m2tkx16cZ demo_jar]# docker build -t demo:1 . 运行镜像: [root@iZuf61quxhnlk9m2tkx16cZ de...

Canaan_
今天
2
0
Redis radix tree源码解析

Redis实现了不定长压缩前缀的radix tree,用在集群模式下存储slot对应的的所有key信息。本文将详述在Redis中如何实现radix tree。 核心数据结构 raxNode是radix tree的核心数据结构,其结构体...

阿里云云栖社区
今天
13
0
vue import 传入变量

在做动态添加component的时候,传入变量就会报错,出现以下错误信息: vue-router.esm.js?fe87:1921 Error: Cannot find module '@/components/index'. at eval (eval at ./src/components ......

朝如青丝暮成雪
今天
3
0
Flutter开发 Dio拦截器实现token验证过期的功能

前言: 之前分享过在Android中使用Retrofit实现token失效刷新的处理方案,现在Flutter项目也有“token验证过期”的需求,所以接下来我简单总结一下在Flutter项目中如何实现自动刷新token并重...

EmilyWu
今天
9
0
final Map可以修改内容,final 常量不能修改

1.final Map 可以put元素,但是不可以重新赋值 如: final Map map = new HashMap(); map = new HashMap();//不可以 因为栈中变量map引用地址不能修改 2.final str = “aa”; str = "bb";/......

qimh
今天
4
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部