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

基于Servlet应用使用pac4j-oidc获取Azure AD应用角色求助

在Servlet应用中通过pac4j获取Azure AD的appRoles

我在基于Servlet的应用中使用javaee-pac4j:7.1.0和pac4j-oidc:5.7.0,通过OIDC对接Azure AD实现认证。目前已成功跳转至Azure完成认证,回调接口也能获取到登录用户的基础信息,但不清楚如何获取Azure AD中定义的appRoles。业务流程需要这些应用角色来完成应用内的用户与角色映射,参考jee-pac4j-demo后仍无头绪,附上相关配置代码请求指导:

相关配置代码

web.xml

<filter>
    <filter-name>callbackFilter</filter-name>
    <filter-class>com.xxx.yyy.security.oidc.CallbackFilter</filter-class>

    <init-param>
        <param-name>renewSession</param-name>
        <param-value>true</param-value>
    </init-param>
    <init-param>
        <param-name>multiProfile</param-name>
        <param-value>true</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>callbackFilter</filter-name>
    <url-pattern>/oidc/rest/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>
<filter>
    <filter-name>JwtParameterFilter</filter-name>
    <filter-class>org.pac4j.jee.filter.SecurityFilter</filter-class>
    <init-param>
        <param-name>configFactory</param-name>
        <param-value>com.xxx.yyy.security.oidc.DemoConfigFactory</param-value>
    </init-param>
    <init-param>
        <param-name>authorizers</param-name>
        <param-value>custom</param-value>
    </init-param>
    <init-param>
        <param-name>clients</param-name>
        <param-value>OidcClient</param-value>
    </init-param>
</filter>
<filter-mapping>
    <filter-name>JwtParameterFilter</filter-name>
    <url-pattern>/rest/rest-jwt/*</url-pattern>
    <dispatcher>REQUEST</dispatcher>
</filter-mapping>

DemoConfigFactory.java

@Override
public Config build(final Object... parameters) {

    System.out.print("Building Security configuration...\n");

    oidcConfiguration = new OidcConfiguration();
    oidcConfiguration.setClientId("sdfdsf-02f9-401f-bbf3-dd87d64a6a2a");
    oidcConfiguration.setSecret("iGc8Q~wZ_~dffsdfsdfs");
    oidcConfiguration.setDiscoveryURI("https://login.microsoftonline.com/sdfsdfs-2cb0-44dc-88cd-fdfs/v2.0/.well-known/openid-configuration");
    oidcConfiguration.setUseNonce(true);
    oidcConfiguration.addCustomParam("prompt", "consent");

    oidcClient = new OidcClient(oidcConfiguration);
   /* oidcClient.setAuthorizationGenerator((webContext, sessionStore, userProfile) -> {
                userProfile.addRole("ConfiguratorOne");
                return java.util.Optional.of(userProfile);
            }
            );*/

    // REST authent with JWT for a token passed in the url as the token parameter
    final List<SignatureConfiguration> signatures = new ArrayList<>();
    signatures.add(new SecretSignatureConfiguration(JWT_SALT));
    ParameterClient parameterClient = new ParameterClient("token", new JwtAuthenticator(signatures));
    parameterClient.setSupportGetRequest(true);
    parameterClient.setSupportPostRequest(false);

    final Clients clients = new Clients("https://localhost:8443/myapplication/oidc/rest/sp/consumer", oidcClient);
    final Config config = new Config(clients);
    config.addAuthorizer("custom", new CustomAuthorizer());
    return config;
}

CallbackFilter.java

@WebFilter(filterName = "CallbackFilter", urlPatterns = {"/oidc/rest/*", "/oidc/rest"})
public class CallbackFilter extends AbstractConfigFilter implements javax.servlet.Filter {

    private static final Log LOG = LogFactory.getLog(CallbackFilter.class);
    private static final String AUTHENTICATED_SESSION_ATTRIBUTE = "authenticated";
    private ProfileManager profileManager;

    @Inject
    private DemoConfigFactory demoConfigFactory;

    @Override
    public void doFilter(final ServletRequest request, final ServletResponse response,
                         final FilterChain chain) throws IOException, ServletException {

        final HttpServletRequest req = (HttpServletRequest) request;
        final HttpServletResponse resp = (HttpServletResponse) response;
        this.internalFilter(req, resp, chain);
        UserProfile userProfile = profileManager.getProfile().get();

        LOG.info("OIDC response received" + userProfile.getUsername());

        LOG.info("" + userProfile.getRoles().toString());
        String authenticatedUser = userProfile.getUsername();
     
        setAuthenticatedSession(req);
        redirectToGotoURL(req, resp, authenticatedUser);

    }

    @Override
    protected void internalFilter(HttpServletRequest request, HttpServletResponse response, FilterChain chain) throws IOException, ServletException {
        Config config = this.getSharedConfig();
        HttpActionAdapter bestAdapter = FindBest.httpActionAdapter((HttpActionAdapter)null, config, JEEHttpActionAdapter.INSTANCE);
        CallbackLogic bestLogic = FindBest.callbackLogic(this.callbackLogic, config, DefaultCallbackLogic.INSTANCE);
        WebContext context = FindBest.webContextFactory((WebContextFactory)null, config, JEEContextFactory.INSTANCE).newContext(new Object[]{request, response});
        SessionStore sessionStore = FindBest.sessionStoreFactory((SessionStoreFactory)null, config, JEESessionStoreFactory.INSTANCE).newSessionStore(new Object[]{request, response});
        bestLogic.perform(context, sessionStore, config, bestAdapter, this.defaultUrl, this.renewSession, this.defaultClient);
        profileManager = new ProfileManager(context,sessionStore);
      
    }
}

解决方案

1. 确认Azure AD端配置

首先确保Azure AD应用注册中:

  • 已为目标用户/组分配了定义好的appRoles
  • 应用的ID Token或Access Token中包含roles声明(可通过Azure AD的"令牌配置"页面确认)

2. 配置pac4j自动映射角色

有两种方式让pac4j从OIDC响应中提取Azure AD的appRoles:

方式一:直接配置角色属性名称

在DemoConfigFactory的oidcConfiguration配置中添加一行,指定角色对应的属性名:

oidcConfiguration.setRoleAttribute("roles");

这样pac4j会自动将ID Token中的roles声明值添加到用户的角色列表中。

方式二:自定义AuthorizationGenerator

如果需要对角色做额外处理(比如转换为内部角色名),可以使用AuthorizationGenerator:
取消DemoConfigFactory中注释的代码块并修改:

oidcClient.setAuthorizationGenerator((webContext, sessionStore, userProfile) -> {
    // 从用户属性中获取Azure AD返回的roles列表
    List<String> azureRoles = (List<String>) userProfile.getAttribute("roles");
    if (azureRoles != null) {
        // 可在此处添加角色转换逻辑
        azureRoles.forEach(userProfile::addRole);
    }
    return java.util.Optional.of(userProfile);
});

3. 验证角色获取结果

CallbackFilter中已有打印角色的日志代码:

LOG.info("" + userProfile.getRoles().toString());

启动应用完成认证后,查看日志即可确认是否成功获取到Azure AD的appRoles。

4. 应用内角色映射(可选)

如果需要将Azure AD的角色转换为应用内部的角色体系,可在AuthorizationGenerator中添加转换逻辑:

oidcClient.setAuthorizationGenerator((webContext, sessionStore, userProfile) -> {
    List<String> azureRoles = (List<String>) userProfile.getAttribute("roles");
    if (azureRoles != null) {
        for (String azureRole : azureRoles) {
            // 根据实际业务映射角色
            switch(azureRole) {
                case "Azure_Admin":
                    userProfile.addRole("APP_ADMIN");
                    break;
                case "Azure_User":
                    userProfile.addRole("APP_USER");
                    break;
                default:
                    userProfile.addRole(azureRole);
            }
        }
    }
    return java.util.Optional.of(userProfile);
});

内容的提问来源于stack exchange,提问作者Gaurav

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.07.20 00:34:57