使用 OpenID Connect 保护采用 Microsoft Entra ID 的 WebSphere Liberty/Open Liberty 应用程序

本文展示如何使用 OpenID Connect (OIDC) 保护采用 Microsoft Entra ID 的 IBM WebSphere Liberty/Open Liberty 应用程序。

在本文中,学习如何:

  • 使用 Microsoft Entra ID 设置 OIDC 提供程序。
  • 使用 OIDC 保护 WebSphere Liberty/Open Liberty 应用。
  • 运行并测试 WebSphere Liberty/Open Liberty 应用。

先决条件

使用 Microsoft Entra ID 设置 OIDC 提供程序

OpenID Connect 是 Microsoft Entra ID 支持的行业标准身份验证协议。 在本部分中,将使用 Microsoft Entra ID 设置 OIDC 提供程序,以便与 WebSphere Liberty/Open Liberty 应用一起使用。 在后面的部分中,将使用 OIDC 配置 WebSphere Liberty/Open Liberty 应用,以便在 Microsoft Entra 租户中对用户进行身份验证和授权。

在 Microsoft Entra 租户中创建用户

首先,按照如何创建、邀请和删除用户中的步骤在 Microsoft Entra 租户中创建两个用户。 只用参阅创建新用户部分。 在阅读本文时使用以下说明,然后在 Microsoft Entra 租户中创建用户后返回到本文。

要创建一个用户作为应用中的“管理员”,请执行以下步骤:

  1. 在“创建新用户”部分中到达“基本信息”选项卡时,请执行以下步骤:
    1. 在“用户主体名称”中,输入 admin。保存该值,以便以后登录应用时使用。

    2. 对于“邮件别名,请选择”从用户主体名称派生”。

    3. 对于“显示名称”,请输入“Admin”。

    4. 对于“密码”,请选择“自动生成密码”。 复制并保存“密码”值,以便以后登录应用时使用。

    5. 选择“已启用帐户”。

      Azure 门户的屏幕截图,显示了为管理员用户创建新用户“基本信息”的窗格。

    6. 选择“查看 + 创建”“创建”。 等待用户创建完成。

    7. 等待一分钟左右,然后选择“刷新”。 应该会在列表中看到新用户。

要创建一个用户作为应用中的“用户”,请重复上述步骤,但要使用以下值:

  • 用户主体名称中,输入 user
  • 显示名称中,输入 User

Azure 门户的屏幕截图,显示了为一般用户创建新用户“基本信息”的窗格。

在 Microsoft Entra ID 中注册应用程序

接下来,按照快速入门:向 Microsoft 标识平台注册应用程序中的步骤注册应用程序。 阅读本文时请遵循以下说明,然后在注册并配置应用程序后返回本文。

  1. 在到达注册应用程序部分时,请按照以下步骤操作:
    1. 对于“支持的帐户类型”,选择“仅此组织目录中的帐户(仅默认目录 - 单租户)”。
    2. 注册完成后,保存“应用程序(客户端)ID”和“目录(租户)ID”值,以便以后在应用配置中使用。
  2. 到达“添加重定向 URI”部分时,现在跳过以下步骤。 稍后在本文中,在本地运行和测试示例应用时将添加重定向 URI。
  3. 在到达“添加凭据”部分时,选择“添加客户端机密”选项卡。
  4. 在添加客户端密码时,请记下“客户端机密”值,以便稍后在应用配置中使用。

向应用程序添加应用角色

然后,按照为应用程序添加应用角色并在令牌中接收中的步骤为应用程序添加应用角色。 只需要部分为应用程序声明角色将用户和组分配给 Microsoft Entra 角色。 阅读本文时请遵循以下说明,然后在声明应用程序的角色后返回本文。

  1. 为应用程序声明角色部分中,使用应用角色 UI 为管理员和一般用户创建角色。

    1. 使用以下值创建管理员用户角色:

      • 对于“显示名称”,请输入“Admin”。
      • 对于“允许的成员类型”,请选择“用户/组”。
      • 对于“值”,输入“管理员”。
      • 在“说明”中,输入“Admin”。
      • 选择要启用此应用角色吗?

      显示管理员用户的“创建应用角色”窗格的 Azure 门户的屏幕截图。

    2. 选择“应用”。 等待角色创建完成。

    3. 使用相同的步骤创建一般用户角色,但要使用以下值:

      • 显示名称中,输入 User
      • 在“值”中,输入“user”。
      • 在“说明”中,输入“User”。

      显示一般用户的“创建应用角色”窗格的 Azure 门户的屏幕截图。

  2. 在访问将用户和组分配给 Microsoft Entra 角色部分时,请执行以下步骤:

    1. 选择“添加用户/组”。

    2. 在“添加分配”窗格中,对于“用户”,请选择用户“Admin”,而对于“选择角色”,请选择角色“Admin”。然后选择“分配”。 等待应用程序分配成功。 可能需要向侧滚动表才能查看“角色分配”列。

    3. 重复前面的步骤,将 User 角色分配给用户 User

    4. 选择“刷新”,应该会在“用户和组”窗格中看到分配的用户和角色。

      显示了已分配的用户和角色的 Azure 门户的屏幕截图。

      可能需要调整列标题的宽度才能让视图看起来像图像。

请不要遵循将应用角色添加到应用程序并在令牌中接收它们中的任何其他步骤。

使用 OpenID Connect 保护 WebSphere Liberty/Open Liberty 应用

在本部分中,将使用 OIDC 保护 WebSphere Liberty/Open Liberty 应用,该应用会对 Microsoft Entra 租户中的用户进行身份验证和授权。 你还将学习如何使用基于角色的访问控制 (RBAC) 授予用户对应用某些部分的访问权限。 该应用使用 Jakarta Servlet 规范的编程安全策略配置。 Jakarta EE 还支持 RESTful Web 服务。 有关保护 RESTful Web 服务应用程序的文章参考,请参阅后续步骤部分。

本快速入门的示例 WebSphere Liberty/Open Liberty 应用在 GitHub 上,位于 liberty-entra-id 存储库中。

启用身份验证和授权以保护应用

应用在 index.html 中定义了一个欢迎页面资源,如下面的示例代码所示。 未经身份验证的用户可以访问此页面。 欢迎页面的根路径位于 /

<!DOCTYPE html>
<html>
<head>
    <meta charset="UTF-8">
    <title>Greeting</title>
</head>
<body>
<h1>Hello, welcome to Open Liberty/WebSphere Liberty and Microsoft Entra ID integration!</h1>
<h1>
    <a href="/profile/user">Sign in as user</a>
</h1>
<h1>
    <a href="/profile/admin">Sign in as admin</a>
</h1>
</body>
</html>

从欢迎页面中,用户可以登录应用并访问配置文件页面。 欢迎页面包含以用户或管理员身份登录的链接。链接分别位于 /profile/user/profile/admin

/profile/user/profile/admin 链接都指向在 ProfileServlet.java 中定义的配置文件 servlet,如下面的示例代码所示。 此 servlet 只能由经过身份验证的用户使用批注 jakarta.servlet.annotation.ServletSecurity 和批注 jakarta.servlet.annotation.HttpConstraint 访问。 属性 rolesAllowed = {"users"} 指定只有具有安全角色 users 且经过身份验证的用户才能访问 /profile 路径。 系统会自动在 Liberty 配置文件 users 中为经过身份验证的用户分配 角色。

package com.example;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.HttpConstraint;
import jakarta.servlet.annotation.ServletSecurity;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

import com.ibm.websphere.security.social.UserProfileManager;
import java.util.List;

@WebServlet(name = "ProfileServlet", urlPatterns = {"/profile/user","/profile/admin"})
@ServletSecurity(value = @HttpConstraint(rolesAllowed = {"users"},
        transportGuarantee = ServletSecurity.TransportGuarantee.CONFIDENTIAL))
public class ProfileServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        List<?> roles = UserProfileManager.getUserProfile().getIdToken().getClaims().getClaim("roles",
                List.class);

        String path = request.getServletPath();
        if (path.equals("/profile/admin") && (null == roles || !roles.contains("admin"))) {
            response.sendError(HttpServletResponse.SC_FORBIDDEN);
            return;
        }

        String username = request.getUserPrincipal().getName();
        request.setAttribute("name", username);
        request.setAttribute("roles", roles);

        request
                .getRequestDispatcher("/profile.jsp")
                .forward(request, response);
    }
}

配置文件 servlet 会从 ID 令牌检索用户的角色,并且会在用户尝试访问 admin 路径时检查用户是否具有 /profile/admin 角色。 如果用户没有 admin 角色,则 servlet 将返回“403 禁止访问”错误。 在其他情况下,servlet 将检索用户的名称,并将请求转发到具有用户的名称和角色的配置文件页面。

配置文件页面可在 profile.jsp 中定义,如下例所示。 此页面显示用户的名称和角色。 配置文件页面在 /logout 还有一个注销链接。 配置文件页面是编写的 JSP (Jakarta Server Pages)。 请注意页面中 ${} 表达式的使用。 ${} 指示使用 Jakarta 表达式语言 (EL)。 呈现页面时,EL 表达式将被替换为对应变量的值。 有关 EL 规范的参考,请参阅后续步骤部分。

<%@ taglib prefix="c" uri="jakarta.tags.core" %>
<%@ page contentType="text/html;charset=UTF-8"%>
<html>
<head>
    <meta charset="UTF-8">
    <title>Profile</title>
</head>
<body>
<h1>Hello, ${name}</h1>
<h2>Roles</h2>
<ul>
    <c:forEach var="role" items="${roles}">
        <li>${role}</li>
    </c:forEach>
</ul>
<h1>
    <b><a href="/logout">Sign out</a></b>
</h1>
</body>
</html>

当用户选择注销链接时,应用将调用在 LogoutServlet.java 中定义的注销 servlet,如以下示例代码所示。 注销 servlet 会调用 request.logout() 方法来注销用户,然后将用户重定向到欢迎页面。

package com.example;

import jakarta.servlet.ServletException;
import jakarta.servlet.annotation.HttpConstraint;
import jakarta.servlet.annotation.ServletSecurity;
import jakarta.servlet.annotation.WebServlet;
import jakarta.servlet.http.HttpServlet;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import java.io.IOException;

@WebServlet(name = "LogoutServlet", urlPatterns = "/logout")
@ServletSecurity(value = @HttpConstraint(rolesAllowed = {"users"},
        transportGuarantee = ServletSecurity.TransportGuarantee.CONFIDENTIAL))
public class LogoutServlet extends HttpServlet {

    private static final long serialVersionUID = 1L;

    @Override
    protected void doGet(HttpServletRequest request, HttpServletResponse response)
            throws IOException, ServletException {

        request.logout();
        response.sendRedirect("/");
    }
}

运行并测试 WebSphere Liberty/Open Liberty 应用

在本部分中,将运行并测试 WebSphere Liberty/Open Liberty 应用,以了解它如何与 Microsoft Entra ID 作为 OIDC 提供程序配合使用。

向应用注册中添加重定向 URI

若要在本地成功运行和测试应用,需要向应用注册添加重定向 URI。 按照快速入门:将应用程序注册到 Microsoft 标识平台添加重定向 URI 部分中的说明执行操作,并使用以下值:

  • 在“配置平台”中,选择“Web”。
  • 对于“重定向 URI”,请输入

准备示例

按照以下步骤准备示例应用:

  1. 使用以下命令从 GitHub 克隆该示例应用:

    git clone https://github.com/Azure-Samples/liberty-entra-id
    cd liberty-entra-id
    git checkout 2024-09-26
    

    如果你看到一条关于处于 detached HEAD 状态的消息,可以放心忽略此消息。 此消息仅表示签出了一个标签。

  2. 使用以下命令来定义以下环境变量以及之前记下的值:

    export CLIENT_ID==<application/client-ID>
    export CLIENT_SECRET=<client-secret>
    export TENANT_ID=<directory/tenant-ID>
    

    这些环境变量为 WebSphere Liberty/Open Liberty 中内置的 OIDC 支持提供了值。 以下示例显示了 Liberty server.xml 中的对应 OIDC 配置。

     <oidcLogin
         id="liberty-entra-id" clientId="${client.id}"
         clientSecret="${client.secret}"
         discoveryEndpoint="https://login.microsoftonline.com/${tenant.id}/v2.0/.well-known/openid-configuration"
         signatureAlgorithm="RS256"
         userNameAttribute="preferred_username" />
    

    如果未在配置文件中定义变量的值,则 WebSphere Liberty/Open Liberty 会按照其命名约定从环境变量中读取值。 有关命名转换的详细信息,请参阅变量替换优先级

运行 WebSphere Liberty/Open Liberty 应用

可以使用 liberty-maven-plugin 运行应用。 若要运行应用,请选择以下方法之一:

注意

为了使 WebSphere Liberty/Open Liberty 能够连接到 Microsoft Entra ID,请确保在定义上一节中显示的环境变量的 shell 中运行该命令。

  • 在开发模式下运行应用:

    mvn liberty:dev
    
  • 在运行时模式下运行应用:

    mvn liberty:run
    

如果要尝试不同的模式,请使用 Ctrl+C 停止应用,然后以另一种模式运行应用。

测试 WebSphere Liberty/Open Liberty 应用

运行应用后,使用专用选项卡打开 Web 浏览器并导航到 https://localhost:9443。 由于证书是自签名证书,因此可能会看到有关证书的警告。 可以放心地忽略警告并继续访问站点。

此时应该会出现欢迎页面,其中包含以用户或管理员身份登录的链接。使用专用选项卡可避免污染您在常规浏览器中可能存在的任何现有 Microsoft Entra ID 活动。

显示欢迎页面的示例应用程序的屏幕截图。

收集两个用户的凭据

在本文中,Microsoft Entra ID 使用每个用户的电子邮件地址作为登录的用户 ID。 按照以下步骤获取管理员用户和一般用户的电子邮件地址:

  1. 至少以云应用程序管理员身份登录到 Microsoft Entra 管理中心
  2. 如果你有权访问多个租户,请使用顶部菜单中的“设置”图标 (),通过“目录 + 订阅”菜单切换到你希望在其中注册应用程序的租户。
  3. 浏览到“标识”“用户”“所有用户”。>>
  4. 在列表中找到管理员用户并选择它。
  5. 找到“用户主体名称”字段。
  6. 使用字段值旁边的复制图标将用户的电子邮件地址保存到剪贴板。 保存该值以供以后使用。
  7. 要获取一般用户的电子邮件地址,请按照相同的步骤操作。

使用创建用户时设置的管理员用户和一般用户的密码。

练习应用的功能

按照以下步骤练习功能:

  1. 选择“以用户身份登录”链接。 使用之前创建的一般用户登录。 登录后,Microsoft Entra ID 会重定向到配置文件页面,在这里可以看到名称和角色。

    显示用户配置文件的示例应用程序的屏幕截图。

  2. 如果这是第一次登录,系统会提示更新密码。 按照说明更新密码。

  3. 如果系统提示“你的组织需要其他安全信息。请按照提示下载并设置 Microsoft Authenticator 应用程序”,则可以选择“稍后询问”继续测试。

  4. 如果系统提示“请求的权限”,请查看应用程序请求的权限。 选择“接受”以继续测试。

  5. 选择“注销”,从应用注销。 注销后,会重定向到欢迎页面。

  6. 选择“以管理员身份登录”链接。 Microsoft Entra ID 会重定向到登录页面。 使用之前创建的管理员用户登录。 登录后,Microsoft Entra ID 会重定向到类似的配置文件页面,但具有不同的角色 admin

    显示管理员配置文件的示例应用程序的屏幕截图。

  7. 再次注销,然后尝试使用之前创建的一般用户以管理员身份登录。 应该会出现一条错误消息,因为一般用户没有 admin 角色。

    显示访问被拒绝消息的示例应用程序的屏幕截图。

清理资源

本文并未指导在 Azure 上部署应用。 尽管 Microsoft Entra ID 资源,但没有应用可清理的 Azure 资源。 若要在 Azure 上部署应用,可以遵循下一部分中的指导。

完成此示例应用的资源后,按照以下步骤清理 Microsoft Entra ID 资源。 删除未使用的 Microsoft Entra ID 资源是一种重要的安全最佳做法。

  1. 按照“删除在 Microsoft 标识平台注册的应用程序”中的步骤删除创建的应用注册。 只需按照删除组织编写的应用程序部分中的步骤进行操作即可。
  2. 删除应用注册的行为也应删除企业应用程序。 有关删除企业应用程序的详细信息,请参阅删除企业应用程序
  3. 按照如何创建、邀请和删除用户中的步骤删除所创建的用户。

后续步骤

在本快速入门中,将使用 OIDC 保护采用 Microsoft Entra ID 的 WebSphere Liberty/Open Liberty 应用程序。 有关详细信息,请浏览以下资源: