CAS 7.0.2集成GitHub身份委托时TicketGrantingTicketImpl反序列化错误求助
CAS 7.0.2 GitHub委托认证Redis存储Ticket反序列化错误问题
问题描述
在CAS 7.0.2中配置GitHub作为委托身份提供商,账号授权流程可正常完成,但控制台持续抛出TicketGrantingTicketImpl反序列化错误(Ticket存储于Redis)。
错误日志
2024-03-26 15:05:02,752 ERROR [org.apereo.cas.util.serialization.AbstractJacksonBackedStringSerializer] - <Cannot read/parse [{"@class":"org.apereo.cas.ticket.TicketGrantingTicketImpl","@id":1,"id":"TGT-1-********qFm6SjQ17y...] to deserialize into type [class org.apereo.cas.ticket.TicketGrantingTicketImpl]. This may be caused in the absence of a configuration/support module that knows how to interpret the fragment, specially if the fragment describes a CAS registered service definition. Internal parsing error is [Cannot construct instance of `org.pac4j.oauth.credentials.OAuth20Credentials` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 2090] (through reference chain: org.apereo.cas.ticket.TicketGrantingTicketImpl["authentication"]->org.apereo.cas.authentication.DefaultAuthentication["credentials"]->java.util.ArrayList[0]->org.apereo.cas.authentication.principal.ClientCredential["credentials"])]> 2024-03-26 15:05:02,758 ERROR [org.apereo.cas.ticket.registry.DefaultTicketRegistryCleaner] - <INVALID_TICKET DefaultTicketStringSerializationManager.java:deserializeTicket:60 DefaultTicketStringSerializationManager.java:lambda$deserializeTicket$1:49 Unchecked.java:lambda$supplier$38:1695 > 2024-03-26 15:05:52,249 INFO [org.apereo.cas.services.mgmt.AbstractServicesManager] - <Loaded [2] service(s) from [EmbeddedResourceBasedServiceRegistry].> 2024-03-26 15:06:35,242 ERROR [org.apereo.cas.util.serialization.AbstractJacksonBackedStringSerializer] - <Cannot read/parse [{"@class":"org.apereo.cas.ticket.TicketGrantingTicketImpl","@id":1,"id":"TGT-1-********qFm6SjQ17y...] to deserialize into type [class org.apereo.cas.ticket.TicketGrantingTicketImpl]. This may be caused in the absence of a configuration/support module that knows how to interpret the fragment, specially if the fragment describes a CAS registered service definition. Internal parsing error is [Cannot construct instance of `org.pac4j.oauth.credentials.OAuth20Credentials` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 2090] (through reference chain: org.apereo.cas.ticket.TicketGrantingTicketImpl["authentication"]->org.apereo.cas.authentication.DefaultAuthentication["credentials"]->java.util.ArrayList[0]->org.apereo.cas.authentication.principal.ClientCredential["credentials"])]> 2024-03-26 15:06:35,342 ERROR [org.apereo.cas.util.serialization.AbstractJacksonBackedStringSerializer] - <Cannot read/parse [{"@class":"org.apereo.cas.ticket.TicketGrantingTicketImpl","@id":1,"id":"TGT-1-********qFm6SjQ17y...] to deserialize into type [class org.apereo.cas.ticket.TicketGrantingTicketImpl]. This may be caused in the absence of a configuration/support module that knows how to interpret the fragment, specially if the fragment describes a CAS registered service definition. Internal parsing error is [Cannot construct instance of `org.pac4j.oauth.credentials.OAuth20Credentials` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 2090] (through reference chain: org.apereo.cas.ticket.TicketGrantingTicketImpl["authentication"]->org.apereo.cas.authentication.DefaultAuthentication["credentials"]->java.util.ArrayList[0]->org.apereo.cas.authentication.principal.ClientCredential["credentials"])]> 2024-03-26 15:06:35,353 ERROR [org.apereo.cas.util.serialization.AbstractJacksonBackedStringSerializer] - <Cannot read/parse [{"@class":"org.apereo.cas.ticket.TicketGrantingTicketImpl","@id":1,"id":"TGT-1-********qFm6SjQ17y...] to deserialize into type [class org.apereo.cas.ticket.TicketGrantingTicketImpl]. This may be caused in the absence of a configuration/support module that knows how to interpret the fragment, specially if the fragment describes a CAS registered service definition. Internal parsing error is [Cannot construct instance of `org.pac4j.oauth.credentials.OAuth20Credentials` (although at least one Creator exists): cannot deserialize from Object value (no delegate- or property-based Creator) at [Source: REDACTED (`StreamReadFeature.INCLUDE_SOURCE_IN_LOCATION` disabled); line: 1, column: 2090] (through reference chain: org.apereo.cas.ticket.TicketGrantingTicketImpl["authentication"]->org.apereo.cas.authentication.DefaultAuthentication["credentials"]->java.util.ArrayList[0]->org.apereo.cas.authentication.principal.ClientCredential["credentials"])]> 2024-03-26 15:06:52,256 INFO [org.apereo.cas.services.mgmt.AbstractServicesManager] - <Loaded [2] service(s) from [EmbeddedResourceBasedServiceRegistry].>
排查信息
org.pac4j.oauth.credentials.OAuth20Credentials类(来自org.pac4j.pac4j-oauth:6.0.0)默认无无参构造器- 该逻辑在CAS 6.6.0版本中可正常运行
当前GitHub委托认证配置
cas.authn.pac4j.github.id=xxx cas.authn.pac4j.github.secret=xxx cas.authn.pac4j.github.client-name=github cas.authn.pac4j.github.callback-url=https://xxx.goho.co
解决方法
方法1:自定义Jackson模块支持OAuth20Credentials序列化/反序列化
创建自定义Jackson模块,为OAuth20Credentials类指定使用带参构造器完成反序列化:
import com.fasterxml.jackson.databind.module.SimpleModule; import org.pac4j.oauth.credentials.OAuth20Credentials; import com.fasterxml.jackson.databind.deser.BeanDeserializerModifier; import com.fasterxml.jackson.databind.deser.ValueInstantiator; import com.fasterxml.jackson.databind.deser.std.StdValueInstantiator; import com.fasterxml.jackson.databind.introspect.AnnotatedClass; import com.fasterxml.jackson.databind.introspect.AnnotatedConstructor; import java.util.List; public class Pac4jOAuth20CredentialsModule extends SimpleModule { public Pac4jOAuth20CredentialsModule() { super("Pac4jOAuth20CredentialsModule"); setDeserializerModifier(new BeanDeserializerModifier() { @Override public ValueInstantiator modifyValueInstantiator(com.fasterxml.jackson.databind.DeserializationConfig config, AnnotatedClass ac, ValueInstantiator defaultInstantiator) { if (ac.getRawType() == OAuth20Credentials.class) { List<AnnotatedConstructor> constructors = ac.getConstructors(); for (AnnotatedConstructor ctor : constructors) { // 匹配OAuth20Credentials的带参构造器(参数为code, token, clientName) if (ctor.getParameterCount() == 3) { return new StdValueInstantiator(config, ac) { @Override public boolean canCreateFromObjectWith() { return true; } }; } } } return defaultInstantiator; } }); } }
将该模块注册到CAS的Spring上下文:
@Bean public Module pac4jOAuth20CredentialsModule() { return new Pac4jOAuth20CredentialsModule(); }
方法2:修改Ticket序列化策略,排除凭证字段
在CAS配置文件中添加配置,让Redis存储Ticket时忽略无法反序列化的凭证字段:
# 排除整个credentials列表 cas.ticket.registry.redis.serialization.exclude-fields=authentication.credentials # 或精准排除嵌套的OAuth20Credentials cas.ticket.registry.redis.serialization.exclude-fields=authentication.credentials[0].credentials
此方法会丢失凭证信息,适合无需回溯凭证的业务场景。
方法3:统一pac4j依赖版本
检查CAS 7.0.2官方依赖管理中指定的pac4j版本,确保项目中pac4j-oauth的版本与CAS官方推荐版本一致,避免版本不兼容导致的序列化问题。
内容的提问来源于stack exchange,提问作者Beer Gold
相关产品推荐
相关产品推荐

