在 Azure Active Directory B2C 中使用 MSAL4J 为 Java JBoss EAP 应用启用登录

本文演示了一个 Java JBoss EAP 应用程序,该应用程序使用 适用于 Java 的 Microsoft 身份验证库(MSAL4J)针对 Azure Active Directory B2C(Azure AD B2C)对用户进行身份验证。

下图显示了应用的拓扑:

显示应用的拓扑的关系图。

应用使用 MSAL4J 登录用户并从 Azure AD B2C 获取 ID 令牌 。 ID 令牌证明用户已通过 Azure AD B2C 租户进行身份验证。

先决条件

建议

设置示例

以下部分演示如何设置示例应用程序。

克隆或下载示例存储库

若要克隆示例,请打开 Bash 窗口并使用以下命令:

git clone https://github.com/Azure-Samples/ms-identity-msal-java-samples.git
cd 3-java-servlet-web-app/1-Authentication/sign-in-b2c

或者,导航到 ms-identity-msal-java-samples 存储库,然后将其下载为 .zip 文件并将其提取到硬盘驱动器。

重要

若要避免 Windows 上的文件路径长度限制,请将存储库克隆或提取到硬盘驱动器根附近的目录中。

将示例应用程序注册到 Azure AD B2C 租户

该示例附带预注册的应用程序,用于测试目的。 若要使用自己的 Azure AD B2C 租户和应用程序,请按照以下部分中的步骤在Azure 门户中注册和配置应用程序。 否则,请继续执行运行示例的步骤

选择要在其中创建应用程序的 Azure AD B2C 租户

若要选择租户,请使用以下步骤:

  1. 登录到 Azure 门户

  2. 如果帐户存在于多个 Azure AD B2C 租户中,请选择Azure 门户角的配置文件,然后选择“切换目录”以将会话更改为所需的 Azure AD B2C 租户。

创建用户流和自定义策略

若要创建常见的用户流,例如注册、登录、配置文件编辑和密码重置,请参阅 教程:在 Azure Active Directory B2C 中创建用户流。

还应考虑 在 Azure Active Directory B2C 中创建自定义策略,但是,这超出了本教程的范围。

添加外部标识提供者

请参阅 教程:将标识提供者添加到 Azure Active Directory B2C 中的应用程序。

注册应用(ms-identity-b2c-java-servlet-webapp-authentication)

若要注册应用,请使用以下步骤:

  1. 导航到Azure 门户并选择 Azure AD B2C

  2. 在导航窗格中选择 “应用注册 ”,然后选择“ 新建注册”。

  3. 显示的“注册应用程序”页 中,输入以下应用程序注册信息:

    • 在“ 名称 ”部分中,输入一个有意义的应用程序名称,以便向应用的用户显示,例如 ms-identity-b2c-java-servlet-webapp-authentication
    • 在“支持的帐户类型”下,选择任何组织目录中的帐户和个人Microsoft帐户(例如 Skype、Xbox、Outlook.com)。
    • “重定向 URI”(可选)部分中,在组合框中选择“Web”,然后输入以下重定向 URI: http://localhost:8080/ms-identity-b2c-java-servlet-webapp-authentication/auth_redirect
  4. 选择“注册”以创建应用程序。

  5. 在应用的注册页上,查找并复制 应用程序(客户端)ID 值以供以后使用。 在应用的配置文件或文件中使用此值。

  6. 选择“保存”以保存更改。

  7. 在应用的注册页上,选择 导航窗格中的“证书和机密 ”,打开可以生成机密并上传证书的页面。

  8. 在“客户端密码”部分中,选择“新建客户端密码” 。

  9. 键入说明 - 例如应用 机密

  10. 选择可用持续时间之一: 1 年2 年内永不过期

  11. 选择 添加 。 将显示生成的值。

  12. 复制并保存生成的值,以便在后续步骤中使用。 代码的配置文件需要此值。 此值不会再次显示,不能通过任何其他方式检索该值。 因此,在导航到任何其他屏幕或窗格之前,请务必将其从Azure 门户保存。

配置应用(ms-identity-b2c-java-servlet-webapp-authentication)以使用应用注册

使用以下步骤配置应用:

注意

在以下步骤中, ClientIDApplication IDAppId相同。

  1. 在 IDE 中打开项目。

  2. 打开 ./src/main/resources/authentication.properties 文件。

  3. 找到该aad.clientId属性,并将现有值替换为应用程序 ID 或clientIdms-identity-b2c-java-servlet-webapp-authentication Azure 门户中的应用程序。

  4. 找到该属性,并将aad.secret现有值替换为在从Azure 门户创建ms-identity-b2c-java-servlet-webapp-authentication应用程序期间保存的值。

  5. 找到该属性,并将 aad.scopes 现有应用程序 clientId 替换为在本部分的步骤 1 中放置 aad.clientId 的值。

  6. 找到该aad.authority属性,并将第一个实例fabrikamb2c替换为在Azure 门户中创建ms-identity-b2c-java-servlet-webapp-authentication应用程序的 Azure AD B2C 租户的名称。

  7. 找到该aad.authority属性,并将第二个实例fabrikamb2c替换为在其中在Azure 门户中创建ms-identity-b2c-java-servlet-webapp-authentication应用程序的 Azure AD B2C 租户的名称。

  8. 找到该aad.signInPolicy属性,并将其替换为在 azure AD B2C 租户中创建的注册/登录用户流策略的名称,在该租户ms-identity-b2c-java-servlet-webapp-authentication中创建应用程序Azure 门户。

  9. 找到该aad.passwordResetPolicy属性,并将其替换为在 azure AD B2C 租户ms-identity-b2c-java-servlet-webapp-authentication中创建的应用程序在Azure 门户中创建的应用程序的密码重置用户流策略的名称。

  10. 找到该aad.editProfilePolicy属性,并将其替换为在 azure AD B2C 租户中创建的编辑配置文件用户流策略的名称,在该租户ms-identity-b2c-java-servlet-webapp-authentication中创建Azure 门户中的应用程序。

生成示例

若要使用 Maven 生成示例,请导航到包含 示例pom.xml 文件的目录,然后运行以下命令:

mvn clean package

此命令生成可在 各种应用程序服务器上运行的 .war 文件。

运行示例

以下部分演示如何将示例部署到Azure App 服务。

先决条件

配置 Maven 插件

部署到 Azure 应用服务的过程会自动使用 Azure CLI 中的 Azure 凭据。 如果未在本地安装 Azure CLI,则 Maven 插件会使用 OAuth 或设备登录来进行身份验证。 有关详细信息,请参阅 Maven 插件的身份验证

使用以下步骤配置插件:

  1. 运行接下来显示的 Maven 命令来配置部署。 此命令将帮助你设置应用服务操作系统、Java 版本和 Tomcat 版本。

    mvn com.microsoft.azure:azure-webapp-maven-plugin:2.12.0:config
    
  2. 对于 “创建新的运行配置”,请按 Y,然后按 Enter

  3. 对于 OS 的“定义”值,请按 2 表示 Linux,然后按 Enter

  4. 对于 javaVersion 的定义值,请按 2 for Java 11,然后按 Enter

  5. 对于 WebContainer 的 Define 值,请按 1 表示 JBosseap7,然后按 Enter

  6. 对于 “定义 pricingTier”值,请按 Enter 选择默认 的 P1v3 层。

  7. 对于 “确认”,请按 Y,然后按 Enter

以下示例显示了部署过程的输出:

Please confirm webapp properties
AppName : msal4j-servlet-auth-1707220080695
ResourceGroup : msal4j-servlet-auth-1707220080695-rg
Region : centralus
PricingTier : P1v3
OS : Linux
Java Version: Java 11
Web server stack: JBosseap 7
Deploy to slot : false
Confirm (Y/N) [Y]:
[INFO] Saving configuration to pom.
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time:  26.196 s
[INFO] Finished at: 2024-02-06T11:48:16Z
[INFO] ------------------------------------------------------------------------

确认选择后,该插件会将插件配置和所需的设置添加到项目的pom.xml文件中,以将应用配置为在Azure App 服务中运行。

pom.xml文件的相关部分应类似于以下示例:

<build>
    <plugins>
        <plugin>
            <groupId>com.microsoft.azure</groupId>
            <artifactId>>azure-webapp-maven-plugin</artifactId>
            <version>x.xx.x</version>
            <configuration>
                <schemaVersion>v2</schemaVersion>
                <resourceGroup>your-resourcegroup-name</resourceGroup>
                <appName>your-app-name</appName>
            ...
            </configuration>
        </plugin>
    </plugins>
</build>

可以直接在pom.xml中修改App 服务的配置。 下表列出了一些常见配置:

properties 必选 说明 版本
schemaVersion false 配置架构的版本。 支持的值为 v1v2 1.5.2
subscriptionId false 订阅的 ID。 0.1.0+
resourceGroup 应用的 Azure 资源组。 0.1.0+
appName 应用的名称。 0.1.0+
region false 托管应用的区域。 默认值为 centralus。 有关有效区域,请参阅 支持的区域 0.1.0+
pricingTier false 应用的定价层。 生产工作负荷的默认值为 P1v2 。 Java 开发和测试的建议最小值是 B2。 有关详细信息,请参阅应用服务定价 0.1.0+
runtime false 运行时环境配置。 有关详细信息,请参阅配置详细信息 0.1.0+
deployment false 部署配置。 有关详细信息,请参阅配置详细信息 0.1.0+

有关配置的完整列表,请参阅插件参考文档。 所有 Azure Maven 插件共享一组常见的配置。 有关这些配置,请参阅 常见配置。 有关特定于Azure App 服务的配置,请参阅 Azure 应用:配置详细信息

请务必保存保留这些 appName 值, resourceGroup 供以后使用。

准备应用进行部署

将应用程序部署到App 服务时,重定向 URL 将更改为已部署的应用实例的重定向 URL。 使用以下步骤更改属性文件中的这些设置:

  1. 导航到应用的 authentication.properties 文件并更改已部署应用的域名的值 app.homePage ,如以下示例所示。 例如,如果在example-domain上一步中选择了应用名称,则现在必须用于https://example-domain.azurewebsites.netapp.homePage该值。 请确保也已将协议从 http 此更改为 https

    # app.homePage is by default set to dev server address and app context path on the server
    # for apps deployed to azure, use https://your-sub-domain.azurewebsites.net
    app.homePage=https://<your-app-name>.azurewebsites.net
    
  2. 保存此文件后,使用以下命令重新生成应用:

    mvn clean package
    

重要

在此相同的 authentication.properties 文件中,你有一个设置 aad.secret。 最好将此值部署到App 服务。 在代码中保留此值并可能将其推送到 git 存储库,这两种做法都不是很好的做法。 若要从代码中删除此机密值,可以在“部署到 App 服务 - 删除机密”部分中找到更详细的指导。 本指南增加了将机密值推送到密钥库并使用密钥库引用的额外步骤。

更新Microsoft Entra ID 应用注册

由于重定向 URI 更改为已部署的应用Azure App 服务,因此还需要更改Microsoft Entra ID 应用注册中的重定向 URI。 若要进行此更改,请使用以下步骤:

  1. 导航到面向开发人员的 Microsoft 标识平台应用注册页

  2. 使用搜索框搜索应用注册 ,例如 java-servlet-webapp-authentication

  3. 通过选择应用名称打开应用注册。

  4. 从菜单中选择“身份验证”。

  5. “Web - 重定向 URI”部分中,选择“添加 URI”。

  6. 填写应用的 URI,追加 /auth/redirect - 例如。 https://<your-app-name>.azurewebsites.net/auth/redirect

  7. 选择“保存”。

部署应用

现在可以将应用部署到Azure App 服务。 使用以下命令确保登录到 Azure 环境以执行部署:

az login

在pom.xml文件中准备好所有配置后,现在可以使用以下命令将 Java 应用部署到 Azure:

mvn package azure-webapp:deploy

部署完成后,应用程序已 http://<your-app-name>.azurewebsites.net/准备就绪。 使用本地 Web 浏览器打开 URL,此时应会看到应用程序的起始页 msal4j-servlet-auth

探索示例

使用以下步骤浏览示例:

  1. 请注意屏幕中心显示的已登录或注销状态。
  2. 选择角落中的上下文敏感按钮。 首次运行应用时,此按钮将 读取登录
  3. 在下一页上,按照说明使用所选标识提供者的帐户登录。
  4. 请注意,上下文敏感按钮现在显示 “注销 ”并显示用户名。
  5. 选择 ID 令牌详细信息 以查看某些 ID 令牌的解码声明。
  6. 还可以选择编辑配置文件。 选择链接可编辑详细信息,例如显示名称、居住地和职业。
  7. 使用角落中的按钮注销。
  8. 注销后,导航到令牌详细信息页的以下 URL: http://localhost:8080/ms-identity-b2c-java-servlet-webapp-authentication/auth_token_details 在这里,可以观察应用如何显示 401: unauthorized 错误而不是 ID 令牌声明。

关于代码

此示例演示如何使用 MSAL4J 将用户登录到 Azure AD B2C 租户。

目录

下表显示了示例项目文件夹的内容:

文件/文件夹 说明
AuthHelper.java 用于身份验证的帮助程序函数。
Config.java 在启动时运行,并配置属性读取器和记录器。
authentication.properties Microsoft Entra ID 和程序配置。
AuthenticationFilter.java 将未经身份验证的请求重定向到受保护的资源到 401 页。
MsalAuthSession 使用 .HttpSession 将所有与 MSAL 相关的会话属性存储在会话属性中。
____Servlet.java 所有可用的终结点在以 ____Servlet.java 结尾.java类中定义。
CHANGELOG.md 示例更改列表。
CONTRIBUTING.md 参与示例的指南。
许可证 示例的许可证。

ConfidentialClientApplication

ConfidentialClientApplication实例在AuthHelper.java文件中创建,如以下示例所示。 此对象有助于创建 Azure AD B2C 授权 URL,并有助于交换访问令牌的身份验证令牌。

IClientSecret secret = ClientCredentialFactory.createFromSecret(SECRET);
confClientInstance = ConfidentialClientApplication
                     .builder(CLIENT_ID, secret)
                     .b2cAuthority(AUTHORITY + policy)
                     .build();

以下参数用于实例化:

  • 应用的客户端 ID。
  • 客户端机密,这是机密客户端应用程序的要求。
  • Azure AD B2C 颁发机构与相应的 UserFlowPolicy 注册、登录、配置文件编辑或密码重置连接。

在此示例中,使用 Config.java 文件中的属性读取器authentication.properties 文件中读取这些值。

分步演练

以下步骤提供应用的功能的演练:

  1. 登录过程的第一步是向 Azure Active Directory B2C 租户的终结点发送请求 /authorize 。 MSAL4J ConfidentialClientApplication 实例用于构造授权请求 URL,应用将浏览器重定向到此 URL,如以下示例所示:

    final ConfidentialClientApplication client = getConfidentialClientInstance(policy);
    final AuthorizationRequestUrlParameters parameters = AuthorizationRequestUrlParameters
        .builder(REDIRECT_URI, Collections.singleton(SCOPES)).responseMode(ResponseMode.QUERY)
        .prompt(Prompt.SELECT_ACCOUNT).state(state).nonce(nonce).build();
    
    final String redirectUrl = client.getAuthorizationRequestUrl(parameters).toString();
    Config.logger.log(Level.INFO, "Redirecting user to {0}", redirectUrl);
    resp.setStatus(302);
    resp.sendRedirect(redirectUrl);
    

    以下列表描述了此代码的功能:

    • AuthorizationRequestUrlParameters:必须设置的参数才能生成 AuthorizationRequestUrl。

    • REDIRECT_URI:收集用户凭据后,Azure AD B2C 会重定向浏览器以及身份验证代码。

    • SCOPES范围 是应用程序请求的权限。

      通常,这三个范围 openid profile offline_access 足以接收 ID 令牌响应。 但是,MSAL4J 要求来自 Azure AD B2C 的所有响应也包含访问令牌。

      为了使 Azure AD B2C 分配访问令牌和 ID 令牌,请求必须包含额外的资源范围。 由于此应用实际上不需要外部资源范围,因此它将自己的客户端 ID 添加为第四个范围,以便接收访问令牌。

      可以在 authentication.properties 文件中找到应用请求的范围的完整列表。

    • ResponseMode.QUERY:Azure AD B2C 可以将响应作为 HTTP POST 请求中的表单参数或 HTTP GET 请求中的查询字符串参数返回。

    • Prompt.SELECT_ACCOUNT:Azure AD B2C 应要求用户选择要对其进行身份验证的帐户。

    • state:应用在每个令牌请求上设置的唯一变量,并在收到相应的 Azure AD B2C 重定向回调后销毁。 状态变量可确保从来自此应用和此会话的 Azure AD B2C 授权请求实际发出 Azure AD B2C 请求 /auth_redirect endpoint ,从而防止 CSRF 攻击。 此操作在 AADRedirectServlet.java 文件中完成。

    • nonce:应用在每个令牌请求的会话中设置的唯一变量,并在收到相应的令牌后销毁。 此 nonce 将转录为分配了 Azure AD B2C 的结果令牌,从而确保没有发生令牌重播攻击。

  2. Azure Active Directory B2C 会显示用户登录提示。 如果登录尝试成功,则用户的浏览器将重定向到应用的重定向终结点。 对此终结点的有效请求包含 授权代码

  3. 然后,该 ConfidentialClientApplication 实例将此授权代码交换为 Azure Active Directory B2C 中的 ID 令牌和访问令牌,如以下示例所示:

    final AuthorizationCodeParameters authParams = AuthorizationCodeParameters
                        .builder(authCode, new URI(REDIRECT_URI))
                        .scopes(Collections.singleton(SCOPES)).build();
    
    final ConfidentialClientApplication client = AuthHelper
            .getConfidentialClientInstance(policy);
    final Future<IAuthenticationResult> future = client.acquireToken(authParams);
    final IAuthenticationResult result = future.get();
    

    以下列表描述了此代码的功能:

    • AuthorizationCodeParameters:必须设置的参数,才能交换 ID 和/或访问令牌的授权代码。
    • authCode:在重定向终结点收到的授权代码。
    • REDIRECT_URI:上一步中使用的重定向 URI 必须再次传递。
    • SCOPES:上一步中使用的范围必须再次传递。
  4. 如果 acquireToken 成功,则会提取令牌声明,并针对会话中存储的 nonce 验证 nonce 声明,如以下示例所示:

    parseJWTClaimsSetAndStoreResultInSession(msalAuth, result, serializedTokenCache);
    validateNonce(msalAuth)
    processSuccessfulAuthentication(msalAuth);
    
  5. 如果成功验证 nonce,身份验证状态将置于服务器端会话中,并利用类公开 MsalAuthSession 的方法,如以下示例所示:

    msalAuth.setAuthenticated(true);
    msalAuth.setUsername(msalAuth.getIdTokenClaims().get("name"));
    

详细信息

有关 OAuth 2.0 协议在此方案中的工作方式和其他方案的详细信息,请参阅 Microsoft Entra ID 的身份验证方案。