做sso时候,集成cas的rememberMe功能时,报错:java.io.NotSerializableException: java.util.HashMap$KeySet。
首先cas集成rememberMe的具体配置可以可以参照【http://blog.youkuaiyun.com/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.youkuaiyun.com/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()));
在集成CAS的rememberMe功能时,使用Redis作为Ticket Registry遇到`java.io.NotSerializableException: java.util.HashMap$KeySet`的问题。错误源于 JDK 中的Set未实现Serializable接口。解决方法涉及CAS配置调整,特别是`deployerConfigContext.xml`中的`authenticationManager`配置和`SuccessfulHandlerMetaDataPopulator.populateAttributes()`方法。需确保所有涉及序列化的对象都实现了Serializable接口。
1047

被折叠的 条评论
为什么被折叠?



