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


		
		
		
		
		
	

	
	
		
		
		
		
	

 

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

 
   

 即可。

 

 

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中增加了配置:

   
	      
	          
	              
	              
	          
	      

 最终错误定位到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 infoMap = null;
	private static ByteArrayOutputStream bos = null;
	private static ObjectOutputStream oos = null;
	@BeforeClass
	public static void setUp() throws IOException{
		infoMap = new HashMap();
		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 set =  infoMap.keySet();
		oos.writeObject(set); 
	}
	
	@Test
	@SuppressWarnings({ "rawtypes", "unchecked" })
	public void testSerializableHashSet() throws IOException{
		/**
		 * HashSet实现了java.io.Serializable接口,支持序列化
		 */
		HashSet 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()));


你可能感兴趣的:(sso)