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

做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()));


猜你喜欢

转载自it-freshman.iteye.com/blog/2286916