启用 Java WebSphere 应用以登录用户并访问 Microsoft Graph

本文演示了一个 Java WebSphere 应用,该应用可让用户登录并获取用于调用 Microsoft Graph 的访问令牌。 它使用适用于 Java 的 Microsoft 身份验证库 (MSAL)

下图显示了应用的拓扑结构:

显示了应用拓扑结构的示意图。

客户端应用使用适用于 Java 的 MSAL (MSAL4J) 登录用户,并从 Microsoft Entra ID 获取 Microsoft Graph访问令牌。 访问令牌证明用户已获授权访问范围中定义的 Microsoft Graph API 终结点。

先决条件

  • Java 8 或更高版本
  • Maven 3
  • Microsoft Entra ID 租户。 有关详细信息,请参阅如何获取 Microsoft Entra ID 租户
  • 如果只想使用组织目录中的帐户,即单租户模式,则使用自己的 Microsoft Entra ID 租户中的用户帐户。 如果尚未在租户中创建用户帐户,则应在继续操作前创建一个帐户。 有关详细信息,请参阅如何创建、邀请和删除用户
  • 如果要使用任何组织目录中的帐户,即在多租户模式下,则需要任何组织的 Microsoft Entra ID 租户中的用户帐户。 必须对该示例进行修改,以便与 Microsoft 个人帐户配合使用。 如果尚未在租户中创建用户帐户,则应在继续操作前创建一个帐户。 有关详细信息,请参阅如何创建、邀请和删除用户
  • 个人 Microsoft 帐户,例如 Xbox、Hotmail、Live 等 - 如果想使用个人 Microsoft 帐户。

建议

设置示例

以下各部分将介绍如何设置示例应用程序。

克隆或下载示例存储库

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

git clone https://github.com/Azure-Samples/ms-identity-msal-java-samples.git
cd 3-java-servlet-web-app/2-Authorization-I/call-graph

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

重要

为避免 Windows 系统对文件路径长度的限制,请将存储库克隆提取到硬盘驱动器根目录附近。

使用 Microsoft Entra ID 租户注册示例应用程序

此示例中有一个项目。 以下各部分将介绍如何使用 Azure 门户注册应用。

选择要在其中创建应用程序的 Microsoft Entra ID 租户

要选择租户,请按以下步骤操作:

  1. 登录到 Azure 门户

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

注册应用 (java-servlet-webapp-call-graph)

首先,按照快速入门:将应用程序注册到 Microsoft 标识平台中的说明在 Azure 门户中注册新应用。

然后,按照以下步骤完成注册:

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

  2. 选择新注册

  3. 在出现的“注册应用程序”页面中,输入以下应用程序注册的信息:

    • 在“名称”部分中,输入一个有意义的应用名称,以便向应用用户显示,例如 java-servlet-webapp-call-graph

    • 在“支持的帐户类型”下,选择以下选项之一:

      • 如果生成的应用程序仅供租户中的用户使用,即单租户应用程序,请选择“仅限此组织目录中的帐户”。
      • 如果希望任何 Microsoft Entra ID 租户中的用户都能使用应用程序(即多租户应用程序),请选择“任何组织目录中的帐户”。
      • 选择“任何组织目录中的帐户和 Microsoft 个人帐户”以包含最广泛的客户,即同时支持 Microsoft 个人帐户的多租户应用程序。
    • 选择“Microsoft 个人帐户”,仅供 Microsoft 个人帐户(例如 Hotmail、Live、Skype 和 Xbox 帐户)用户使用。

    • 在“重定向 URI”部分中,在组合框中选择“Web”并输入以下重定向 URI:http://localhost:8080/msal4j-servlet-graph/auth/redirect

  4. 选择“注册”以创建应用程序。

  5. 在应用的注册页面上,找到并复制“应用程序(客户端) ID”值,以供稍后使用。 可以在应用程序的一个或多个配置文件中使用此值。

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

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

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

  9. 键入描述,例如“应用机密”。

  10. 从可用期限中选择一个:“1 年内”、“2 年内”或“永不过期”。

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

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

  13. 在应用程序的注册页面上,从导航窗格中选择“API 权限”,以便打开页面并添加对应用程序所需的 API 的访问权限。

  14. 选择“添加权限”。

  15. 确保已选择“Microsoft API”选项卡。

  16. 在“常用 Microsoft API”部分,选择“Microsoft Graph”。

  17. 在“委托的权限”部分中,从列表中选择“User.Read”。 如有必要,请使用搜索框。

  18. 选择“添加权限”。


配置应用 (java-servlet-webapp-call-graph) 以使用应用注册

按照以下步骤来配置应用:

注意

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

  1. 在 IDE 中打开项目。

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

  3. 找到字符串 {enter-your-tenant-id-here}。 使用以下值之一替换现有值:

    • Microsoft Entra ID 租户 ID(如果使用“仅限本组织目录中的账户”选项注册应用)。
    • 如果使用“任何组织目录中的帐户”选项来注册应用程序,则显示 organizations 字样。
    • 如果使用“任何组织目录中的帐户和个人 Microsoft 帐户”选项来注册应用程序,则显示 common 字样。
    • 如果使用“个人 Microsoft 帐户”选项来注册应用,则显示 consumers 字样。
  4. 找到字符串 {enter-your-client-id-here},然后用从 Azure 门户复制的应用程序 ID 或 clientId 应用程序的 java-servlet-webapp-call-graph 来替换现有值。

  5. 在 Azure 门户中查找字符串 {enter-your-client-secret-here},并将现有值替换为在创建 java-servlet-webapp-call-graph 应用时保存的值。

生成示例

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

mvn clean package

此命令会生成一个 .war 文件,它可以在各种应用服务器上运行。

运行示例

这些说明假定安装了 WebSphere 并设置了服务器。 可以按照在 Azure 虚拟机上部署 WebSphere 应用服务器(传统)集群中的指导进行基本服务器设置。

在部署到 WebSphere 之前,请按照以下步骤对示例本身进行一些配置更改,然后生成或重新生成包:

  1. 导航到应用的 authentication.properties 文件,并将 app.homePage 的值更改为计划使用的服务器 URL 和端口号,如下例所示:

    # 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://<server-url>:<port-number>/msal4j-servlet-auth/
    
  2. 保存此文件后,使用以下命令重新生成应用:

    mvn clean package
    
  3. 在代码完成生成后,将 .war 文件复制到目标服务器的文件系统中。

还需要在 Azure 应用注册中进行相同的更改,即在 Azure 门户中将其设置为“身份验证”选项卡上的“重定向 URI”值。

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

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

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

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

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

  6. 填写应用程序的 URI,附加 /auth/redirect - 例如 https://<server-url>:<port-number>/auth/redirect

  7. 选择“保存”。

按照以下步骤使用 WebSphere 的集成解决方案控制台部署示例:

  1. 在“应用程序”选项卡上,选择“新建应用程序”,然后选择“新建企业应用程序”。

  2. 选择生成的 .war 文件,然后选择“下一步”,直至到达“映射 Web 模块的上下文根”安装步骤。 其他均可以保留默认设置。

  3. 对于上下文根,将其设置为与在示例配置/Azure 应用注册中设置的“重定向 URI”中端口号之后的值相同。 也就是说,如果重定向 URI 是 http://<server-url>:9080/msal4j-servlet-auth/,那么上下文根应该是 msal4j-servlet-auth

  4. 选择“完成”。

  5. 应用程序安装完成后,转到“应用程序”选项卡的“WebSphere 企业应用程序”部分。

  6. 从应用程序列表中选择已安装的 .war 文件,然后选择“开始”进行部署。

  7. 完成部署后,导航到 http://<server-url>:9080/{whatever you set as the context root},此时就可以看到应用程序。

探索示例

按照以下步骤来探索示例:

  1. 注意屏幕中央显示的登录或退出状态。
  2. 选择角落里的上下文相关按钮。 首次运行应用时,此按钮显示“登录”。
  3. 在下一页上,按照说明使用 Microsoft Entra ID 租户中的帐户登录。
  4. 在同意屏幕上,请注意正在请求的范围。
  5. 请注意,上下文相关按钮现在显示“注销”并显示你的用户名。
  6. 选择“ID 令牌详细信息”以查看一些 ID 令牌的解码声明。
  7. 选择“调用图形”以调用 Microsoft Graph 的 /me 终结点,并查看所获取的一系列用户详细信息。
  8. 使用角落里的按钮注销。

关于代码

本示例使用适用于 Java 的 MSAL (MSAL4J) 登录用户,并获取 Microsoft Graph API 的令牌。 它使用适用于 Java 的 Microsoft Graph SDK 从 Graph 获取数据。 必须使用 Maven 将这些库添加到项目中。

如果要复制此示例的行为,则可以复制 src/main/java/com/microsoft/azuresamples/msal4j 文件夹中的 pom.xml 文件以及 helpersauthservlets 文件夹的内容。 还需要使用 authentication.properties 文件。 这些类和文件包含通用代码,可用于各种应用程序。 也可以复制示例的其他部分,但其他类和文件是专门为实现本示例的目标而生成的。

目录

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

文件/文件夹 说明
src/main/java/com/microsoft/azuresamples/msal4j/callgraphwebapp/ 此目录包含定义应用的后端业务逻辑的类。
src/main/java/com/microsoft/azuresamples/msal4j/authservlets/ 此目录包含用于登录和注销终结点的类。
*Servlet.java 所有可用的终结点都在 Java 类中定义,名称以 Servlet结尾。
src/main/java/com/microsoft/azuresamples/msal4j/helpers/ 用于身份验证的帮助程序类。
AuthenticationFilter.java 将对受保护终结点未经身份验证的请求重定向到 401 页面。
src/main/resources/authentication.properties Microsoft Entra ID 和程序配置。
src/main/webapp/ 此目录包含 UI - JSP 模板
CHANGELOG.md 示例更改的列表。
CONTRIBUTING.md 参与示例的指南。
许可证 示例的许可证。

ConfidentialClientApplication

如下例所示,在 ConfidentialClientApplication 文件中创建了一个 实例。 此对象有助于创建 Microsoft Entra ID 授权 URL,还有助于将身份验证令牌交换为访问令牌。

// getConfidentialClientInstance method
IClientSecret secret = ClientCredentialFactory.createFromSecret(SECRET);
confClientInstance = ConfidentialClientApplication
                     .builder(CLIENT_ID, secret)
                     .authority(AUTHORITY)
                     .build();

以下参数用于实例化:

  • 应用的客户端 ID。
  • 客户端机密,这是机密客户端应用程序的要求。
  • Microsoft Entra ID 颁发机构,其中包括 Microsoft Entra 租户 ID。

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

分步演练

以下步骤介绍了该应用的功能:

  1. 登录过程的第一步是向 Microsoft Entra ID 租户的 /authorize 终结点发送请求。 MSAL4J ConfidentialClientApplication 实例用于构建授权请求 URL。 应用会将浏览器重定向到此 URL,即用户登录的 URL。

    final ConfidentialClientApplication client = getConfidentialClientInstance();
    AuthorizationRequestUrlParameters parameters = AuthorizationRequestUrlParameters.builder(Config.REDIRECT_URI, Collections.singleton(Config.SCOPES))
            .responseMode(ResponseMode.QUERY).prompt(Prompt.SELECT_ACCOUNT).state(state).nonce(nonce).build();
    
    final String authorizeUrl = client.getAuthorizationRequestUrl(parameters).toString();
    contextAdapter.redirectUser(authorizeUrl);
    

    下面列出了该代码的功能:

    • AuthorizationRequestUrlParameters:生成 AuthorizationRequestUrl 时必须设置的参数。
    • REDIRECT_URI:Microsoft Entra ID 在收集用户凭据后会将浏览器以及授权码重定向到哪里。 它必须与 Azure 门户中 Microsoft Entra ID 应用注册的重定向 URI 相匹配
    • SCOPES范围是应用程序请求的权限。
      • 通常,三个范围 openid profile offline_access 就足以接收 ID 令牌响应。
      • 应用程序请求的全部范围列表可在 authentication.properties 文件中找到。 可以添加更多范围,如 User.Read
  2. Microsoft Entra ID 将会向用户显示登录提示。 如果登录尝试成功,用户的浏览器就会重定向到应用的重定向终结点。 向此终结点发出的有效请求包含授权代码

  3. 然后,ConfidentialClientApplication 实例会将此授权代码与 Microsoft Entra ID 的 ID 令牌和访问令牌进行交换。

    // First, validate the state, then parse any error codes in response, then extract the authCode. Then:
    // build the auth code params:
    final AuthorizationCodeParameters authParams = AuthorizationCodeParameters
            .builder(authCode, new URI(Config.REDIRECT_URI)).scopes(Collections.singleton(Config.SCOPES)).build();
    
    // Get a client instance and leverage it to acquire the token:
    final ConfidentialClientApplication client = AuthHelper.getConfidentialClientInstance();
    final IAuthenticationResult result = client.acquireToken(authParams).get();
    

    下面列出了该代码的功能:

    • AuthorizationCodeParameters:为交换 ID 和/或访问令牌的授权代码而必须设置的参数。
    • authCode:在重定向终结点收到的授权代码。
    • REDIRECT_URI:必须再次传递上一步中使用的重定向 URI。
    • SCOPES:必须再次传递上一步中使用的范围。
  4. 如果 acquireToken 成功,则提取令牌声明。 如果 nonce 检查通过,结果将被放入 context - IdentityContextData 的一个实例,并会被保存到会话中。 然后,当应用程序需要访问 IdentityContextData 时,就可以通过 IdentityContextAdapterServlet 的实例从会话中将其实例化,如以下代码所示:

    // parse IdToken claims from the IAuthenticationResult:
    // (the next step - validateNonce - requires parsed claims)
    context.setIdTokenClaims(result.idToken());
    
    // if nonce is invalid, stop immediately! this could be a token replay!
    // if validation fails, throws exception and cancels auth:
    validateNonce(context);
    
    // set user to authenticated:
    context.setAuthResult(result, client.tokenCache().serialize());
    

保护路由

有关示例应用如何筛选路由访问的信息,请参阅 AuthenticationFilter.java。 在 authentication.properties 文件中,app.protect.authenticated 属性包含只有通过身份验证的用户才能访问的以逗号分隔的路由,如下例所示:

# for example, /token_details requires any user to be signed in and does not require special roles or groups claim(s)
app.protect.authenticated=/token_details, /call_graph

调用图形

当用户导航到 /call_graph 时,应用程序会通过 Java Graph SDK 创建 IGraphServiceClient 的实例,并传递已登录用户的访问令牌。 Graph 客户端会将访问令牌置于其请求的 Authorization 标头中。 然后,应用会要求 Graph 客户端调用 /me 端点,以获取当前已登录用户的详细信息。

如果已经拥有 User.Read 范围的 Graph 服务的有效访问令牌,那么只用编写以下代码即可访问 /me 终结点:

//CallGraphServlet.java
User user = GraphHelper.getGraphClient(contextAdapter).me().buildRequest().get();

作用域

范围表明了 Microsoft Entra ID 应用程序请求的访问级别。

根据请求的范围,Microsoft Entra ID 会在登录时向用户显示同意对话。 如果用户同意一个或多个范围并获得了一个令牌,则同意的范围将被编码到生成的 access_token 中。

有关应用程序请求的范围,请参阅 authentication.properties。 默认情况下,应用程序会将范围值设置为 User.Read。 这一特定的 Microsoft Graph API 范围用于访问当前已登录用户的信息。 用于访问此信息的图形终结点为 https://graph.microsoft.com/v1.0/me。 向此终结点发出的任何有效请求都必须在 access_token 标头中带有一个包含范围 User.ReadAuthorization

详细信息

下一步

将 Java WebSphere 应用部署到 Azure 虚拟机上的传统 WebSphere 中