pac4j+Shiro集成报错:无法提取用户profile,attributes节点位置不符
解决pac4j-Shiro集成CAS OAuth2时的用户属性提取错误
问题原因
调用CAS OAuth2接口时出现错误:
org.pac4j.oauth.profile.casoauthwrapper.CasOAuthWrapperProfileDefinition - Unable to extract user profile as no JSON node 'attributes' was found in body
CAS服务端返回的JSON中,attributes节点嵌套在org.apereo.cas.authentication.Authentication.principal路径下,但默认的CasOAuthWrapperProfileDefinition只会在根节点查找该字段,导致无法匹配提取用户属性。
解决方案
方案1:自定义ProfileDefinition适配嵌套属性路径
通过继承CasOAuthWrapperProfileDefinition重写属性提取逻辑,从嵌套路径获取attributes:
- 创建自定义ProfileDefinition类
import org.pac4j.core.exception.TechnicalException; import org.pac4j.oauth.profile.casoauthwrapper.CasOAuthWrapperProfile; import org.pac4j.oauth.profile.casoauthwrapper.CasOAuthWrapperProfileDefinition; import com.fasterxml.jackson.core.JsonProcessingException; import com.fasterxml.jackson.databind.JsonNode; import com.fasterxml.jackson.databind.ObjectMapper; public class CustomCasOAuthWrapperProfileDefinition extends CasOAuthWrapperProfileDefinition { @Override protected JsonNode getAttributesNode(final JsonNode rootNode) { // 从CAS返回的嵌套路径中定位attributes节点 return rootNode.path("org.apereo.cas.authentication.Authentication") .path("principal") .path("attributes"); } @Override public CasOAuthWrapperProfile extractUserProfile(final String body) { CasOAuthWrapperProfile profile = super.extractUserProfile(body); ObjectMapper mapper = new ObjectMapper(); try { JsonNode rootNode = mapper.readTree(body); // 可额外提取其他嵌套字段(如果需要) JsonNode principalNode = rootNode.path("org.apereo.cas.authentication.Authentication") .path("principal"); if (!principalNode.isMissingNode()) { profile.addAttribute("principal_id", principalNode.path("id").asText()); } } catch (JsonProcessingException e) { throw new TechnicalException("Parse CAS OAuth2 response failed", e); } return profile; } }
- 在Shiro配置中替换默认实现
找到Shiro中配置CasOAuthWrapperClient的代码,指定自定义的ProfileDefinition:
CasOAuthWrapperClient casOAuthClient = new CasOAuthWrapperClient(); // 设置CAS OAuth2客户端的基础配置 casOAuthClient.setClientId("your-client-id"); casOAuthClient.setClientSecret("your-client-secret"); casOAuthClient.setCasOAuthUrl("https://your-cas-server/oauth2.0"); // 替换为自定义的ProfileDefinition casOAuthClient.setProfileDefinition(new CustomCasOAuthWrapperProfileDefinition()); // 将客户端加入Pac4j的客户端列表 Clients clients = new Clients("https://your-app/callback", casOAuthClient); Pac4jSubjectFactory subjectFactory = new Pac4jSubjectFactory(); subjectFactory.setClients(clients); // 关联到Shiro的SecurityManager DefaultWebSecurityManager securityManager = new DefaultWebSecurityManager(); securityManager.setSubjectFactory(subjectFactory);
方案2:尝试CAS服务端属性配置调整(可选)
如果能修改CAS服务端配置,可尝试调整OAuth2用户属性的输出结构:
在CAS的cas.properties中添加:
# 设置用户属性视图为完整模式 cas.oauth.user-profile-view-type=FULL # 强制返回所有属性 cas.authn.attribute-repository.core.return-all-attributes=true # 自定义属性映射,将嵌套的attributes提升到根节点 cas.oauth.user-profile-attributes=attributes:org.apereo.cas.authentication.Authentication.principal.attributes
注:该配置是否生效取决于CAS版本,若无法解决,优先使用方案1。
环境适配说明
针对你使用的JDK 14.0.2、TomEE 8.0.14,需确保:
- 自定义类的编译级别与JDK14兼容
- pac4j相关依赖(
pac4j-oauth、pac4j-shiro)的版本与TomEE 8的Servlet/JSP规范兼容
内容的提问来源于stack exchange,提问作者Daniel Maldonado
相关产品推荐
相关产品推荐

