`
it_freshman
  • 浏览: 15271 次
  • 性别: Icon_minigender_1
  • 来自: 合肥
社区版块
存档分类
最新评论

cas 集成redis报错java.io.NotSerializableException: java.util.HashMap$KeySet

    博客分类:
  • sso
阅读更多

做sso时候,集成cas的rememberMe功能时,报错:java.io.NotSerializableException: java.util.HashMap$KeySet。

 首先cas集成rememberMe的具体配置可以可以参照【http://blog.csdn.net/jadyer/article/details/47110353】进行配置,

 

cas集成redis的配置:

1. 配置redis相关bean

<bean id="jedisPoolConfig" class="redis.clients.jedis.JedisPoolConfig">
		<property name="maxTotal" value="1024" />
		<property name="maxIdle" value="200" />
		<property name="maxWaitMillis" value="1000" />
		<property name="testOnBorrow" value="true" />
		<property name="testOnReturn" value="true" />
	</bean>

	<!-- redis的连接池pool,不是必选项:timeout/password -->
	<bean id="jedisPool" class="redis.clients.jedis.JedisPool">
		<constructor-arg index="0" ref="jedisPoolConfig" />
		<constructor-arg index="1" value="127.0.0.1" />
		<constructor-arg index="2" value="6379" type="int" />
		<constructor-arg index="3" value="20"
			type="int" />
	</bean>

 

2.在ticketRegistry.xml将Ticket Registry托管到redis 管理,

 <!--Ticket Registry托管到redis 管理, -->
  <bean id="ticketRegistry" class="com.xxx.xxx.ticketRegistry.RegisTicketRegistry"
		p:tgtTime="3000000"
		p:stTime="300000"
		p:dbnum="8"
		p:pool-ref="jedisPool"
		p:logoutManager-ref="logoutManager"
	/> 

 即可。

 

 

3.RedisTicketRegistry中的addTicket(),执行到oos.writeObject(ticket);  抛出异常 java.io.NotSerializableException: java.util.HashMap$KeySet

public void addTicket( final Ticket ticket) {
		Jedis jedis = pool.getResource();
		jedis.select(Integer.valueOf(dbnum));
		int seconds = 0;
		String key = ticket.getId();
		if (ticket instanceof TicketGrantingTicket) {
			seconds = Integer.valueOf(tgtTime) / 1000;
		} else {
			seconds = Integer.valueOf(stTime) / 1000;
		}
		ByteArrayOutputStream bos = null;
		ObjectOutputStream oos = null;
		try {
			bos = new ByteArrayOutputStream();
			oos = new ObjectOutputStream(bos);
			oos.writeObject(ticket);
		} catch (Exception e) {
			e.printStackTrace();
		} finally {
			try {
				if (null != oos)
					oos.close();
			} catch (Exception e) {
				e.printStackTrace();
			}
		}
		byte[] ticketBytes = bos.toByteArray();
		jedis.set(key.getBytes(), ticketBytes);
		jedis.expire(key.getBytes(), seconds);
		pool.returnResource(jedis);
	}

 

 

4.在执行RedisTicketRegistry.addTicket()方法oos.writeObject(ticket);时候会报错,

java.io.NotSerializableException: java.util.HashMap$KeySet。

 

最终定位错误原因:是在cas+rememberMe配置时候,(具体配置参照【http://blog.csdn.net/jadyer/article/details/47110353】),

deployerConfigContext.xml,authenticationManager中增加了配置:

 <!-- 针对RememberMe需增加的属性配置 -->  
	    <property name="authenticationMetaDataPopulators">  
	        <list>  
	            <bean class="org.jasig.cas.authentication.SuccessfulHandlerMetaDataPopulator"/>  
	            <bean class="org.jasig.cas.authentication.principal.RememberMeAuthenticationMetaDataPopulator"/>  
	        </list>  
	    </property>  

 最终错误定位到SuccessfulHandlerMetaDataPopulator.populateAttributes()方法

public class SuccessfulHandlerMetaDataPopulator implements AuthenticationMetaDataPopulator {
    /** Attribute name containing collection of handler names that successfully authenticated credential. */
    public static final String SUCCESSFUL_AUTHENTICATION_HANDLERS = "successfulAuthenticationHandlers";

    @Override
    public void populateAttributes(final AuthenticationBuilder builder, final Credential credential) {
        builder.addAttribute(SUCCESSFUL_AUTHENTICATION_HANDLERS, builder.getSuccesses().keySet());
    }
}

根本原因是jdk中Set没有实现Serializable不支持序列化,如下test实例:

public class SerializableTest {
	private static Map<String,Object> infoMap = null;
	private static ByteArrayOutputStream bos = null;
	private static ObjectOutputStream oos = null;
	@BeforeClass
	public static void setUp() throws IOException{
		infoMap = new HashMap<String,Object>();
		infoMap.put("name", "张三");
		infoMap.put("age", 18);
		infoMap.put("birthdate", new Date());
		
		bos = new ByteArrayOutputStream();
		
		oos = new ObjectOutputStream(bos);
	}
	

	@Test
	public void testSerializableSet() throws IOException{
		/**
		 * Set 继承Collection > Iterable 不支持序列化
		 * 抛出异常 java.io.NotSerializableException: java.util.HashMap$KeySet
		 */
		Set<String> set =  infoMap.keySet();
		oos.writeObject(set); 
	}
	
	@Test
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void testSerializableHashSet() throws IOException{
		/**
		 * HashSet实现了java.io.Serializable接口,支持序列化
		 */
		HashSet<String> hashSet =  new HashSet(infoMap.keySet());
		oos.writeObject(hashSet);
	}
}

 

最终解决方案:

//builder.addAttribute(SUCCESSFUL_AUTHENTICATION_HANDLERS, builder.getSuccesses().keySet());
builder.addAttribute(SUCCESSFUL_AUTHENTICATION_HANDLERS, new HashSet(builder.getSuccesses().keySet()));


分享到:
评论

相关推荐

    redis5离线安装文件包,包含redis-5.0.14.tar.gz和redis-4.6.0.gem

    # 下载 redis-3.2.1.gem然后本地安装 sudo gem install -l ./redis-3.2.1.gem port 6379 daemonize yes #bind自己的ip bind 192.168.129.101 protected-mode no #启用集群 cluster-enabled yes cluster-config-file ...

    spring-data-redis-2.0.9.RELEASE-API文档-中英对照版.zip

    标签:springframework、data、spring、redis、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和...

    linux redis安装(redis-2.6.14.tar.gz)

    在Linux系统中安装Redis是一个常见的任务,特别是在搭建分布式缓存或数据库系统时。Redis是一款开源、高性能、基于键值对的数据存储系统,广泛应用于数据缓存、消息队列和数据库等多个场景。本教程将详细讲解如何在...

    netty-codec-redis-4.1.74.Final-API文档-中文版.zip

    标签:netty、codec、redis、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心...

    redis-4.0.0.tar.gz

    1. 客户端连接:可以使用内置的`redis-cli`客户端,或第三方工具如`Jedis`(Java)、`StackExchange.Redis`(C#)等。 2. 数据操作:通过命令行或编程接口进行数据的读写操作,如`SET key value`、`GET key`、`LPUSH...

    redis-3.2.11.tar.gz 以及redis-3.3.5.gem

    Redis 是一个高性能的键值数据库,常用于缓存和数据持久化。它的高效性得益于其内存存储特性,以及丰富的数据结构支持,如字符串、哈希、列表、集合和有序集合。Redis-3.2.11.tar.gz 文件是Redis 3.2.11版本的源代码...

    解决报错-org.springframework.data.redis.serializer.SerializationExce

    解决报错_org.springframework.data.redis.serializer.SerializationException_ Could not write_read JSON

    spring-session-data-redis-2.0.4.RELEASE-API文档-中英对照版.zip

    赠送jar包:spring-session-data-redis-2.0.4....标签:springframework、session、spring、data、redis、中英对照文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文

    redis-5.0.4.tar.gz下载及redis安装过程

    redis安装 1: 下载redis-5.0.4.tar.gz 2: 解压源码并进入目录 tar zxvf redis-5.0.4.tar.gz cd redis-5.0.4 3: 不用configure 4: 直接make (如果是32位机器 make 32bit) 查看linux机器是32位还是64位的方法:...

    netty-codec-redis-4.1.73.Final-API文档-中文版.zip

    标签:codec、redis、netty、jar包、java、中文文档; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明精准翻译,请放心...

    jedis-3.3.0.jar

    java.lang.NoSuchMethodError: redis.clients.jedis.ScanResult.getStringCursor()Ljava/lang/String; at org.crazycake.shiro.WorkAloneRedisManager.keys(WorkAloneRedisManager.java:149) at org.crazycake....

    spring-data-redis-2.3.9.RELEASE-API文档-中文版.zip

    标签:springframework、data、spring、redis、中文文档、jar包、java; 使用方法:解压翻译后的API文档,用浏览器打开“index.html”文件,即可纵览文档内容。 人性化翻译,文档中的代码和结构保持不变,注释和说明...

    redis-3.0.7.tar.gz

    下载redis(http://redis.io/) 2.上传到linux 3.在 usr/local下新建文件夹 redis mkdir /usr/local/redis 4.将root下的redis移动到 /usr/local/redis 然后解压 mv redis-3.0.7.tar.gz /usr/local/redis/ cd /...

    redis-5.0.8.tar.gz

    1. **src**:包含Redis服务器的C语言源代码,如`redis-server`(主进程), `redis-cli`(命令行客户端), `redis-benchmark`(性能测试工具)以及`redis-check-dump`和`redis-check-aof`(数据检查工具)等。...

    使用 Laravel + Redis + Node.js + Socket.io 进行实时聊天.zip

    使用 Laravel + Redis + Node.js + Socket.io 进行实时聊天Laravel 实时聊天 用 Laravel 4.2 + Redis + Node.js + Socket.io 编写的实时聊天示例。嗯,这是 Laravel 4.2 + Redis Node.js + Socket.io 中的实时聊天...

    使用简单的 Google Colab 笔记本学习 Redis Enterprise 和 Redis Stack.zip

    常用工具https://redis.io/try-free/免费 Redis 云账号https://redis.io/insight/ Redis 洞察Redis 堆栈https://redis.io/download/文档https://redis.io/docs/latest/ Redis 文档https://redis.io/commands/ Redis ...

    Socket.IO Redis 发射器,允许从另一个 Node.js 进程与一组 Socket.IO 服务器进行通信 .zip

    Socket.IO Redis 发射器 该@socket.io/redis-emitter包允许您轻松地从另一个 Node.js 进程(服务器端)与一组 Socket.IO 服务器进行通信。该发射器还可用于其他编程语言Java...

    socket.io-redis-emitter:Socket.IO Redis发射器,允许与另一个Node.js进程中的一组Socket.IO服务器进行通信

    Socket.IO Redis发射器 @socket.io/redis-emitter软件包使您可以轻松地与另一个Node.js进程(服务器端)中的一组Socket.IO服务器进行通信。 发射器还提供其他编程语言版本: Java: : Python: : PHP: : Golang...

    最新版linux redis-6.2.1.tar.gz

    Redis 是一个高性能的键值对数据库,常被用于构建数据缓存、消息队列和数据库。在Linux系统中,Redis的安装通常涉及下载源码、编译和配置等步骤。这里我们将详细介绍如何处理"最新版linux redis-6.2.1.tar.gz"这个...

    redis-trib.rb

    redis 配置集群必备

Global site tag (gtag.js) - Google Analytics