基于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
相关产品推荐
相关产品推荐

