You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

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:

  1. 创建自定义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;
    }
}
  1. 在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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.03 23:12:35