使用 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 应用。
先决条件
- Azure 订阅。 如果还没有 Azure 订阅,可以在开始前创建一个免费帐户。
- 至少具有云应用程序管理员 Microsoft Entra 角色的 Azure 标识。 有关详细信息,请参阅列出 Microsoft Entra 角色分配和 Microsoft Entra 内置角色。
- 一个 Microsoft Entra 租户。 如果还没有租户,请参阅快速入门:设置租户。
- 一台安装了类似于 Unix 的操作系统(例如 Ubuntu、macOS 或适用于 Linux 的 Windows 子系统)的本地计算机。
- Git。
- 版本为 21 或更高的 Java SE 实现,例如 OpenJDK 的 Microsoft 版本。
- Maven,3.9.3 或更高版本。
使用 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 租户中创建用户后返回到本文。
要创建一个用户作为应用中的“管理员”,请执行以下步骤:
要创建一个用户作为应用中的“用户”,请重复上述步骤,但要使用以下值:
- 在用户主体名称中,输入 user。
- 在显示名称中,输入 User。
在 Microsoft Entra ID 中注册应用程序
接下来,按照快速入门:向 Microsoft 标识平台注册应用程序中的步骤注册应用程序。 阅读本文时请遵循以下说明,然后在注册并配置应用程序后返回本文。
- 在到达注册应用程序部分时,请按照以下步骤操作:
- 对于“支持的帐户类型”,选择“仅此组织目录中的帐户(仅默认目录 - 单租户)”。
- 注册完成后,保存“应用程序(客户端)ID”和“目录(租户)ID”值,以便以后在应用配置中使用。
- 到达“添加重定向 URI”部分时,现在跳过以下步骤。 稍后在本文中,在本地运行和测试示例应用时将添加重定向 URI。
- 在到达“添加凭据”部分时,选择“添加客户端机密”选项卡。
- 在添加客户端密码时,请记下“客户端机密”值,以便稍后在应用配置中使用。
向应用程序添加应用角色
然后,按照为应用程序添加应用角色并在令牌中接收中的步骤为应用程序添加应用角色。 只需要部分为应用程序声明角色和将用户和组分配给 Microsoft Entra 角色。 阅读本文时请遵循以下说明,然后在声明应用程序的角色后返回本文。
在为应用程序声明角色部分中,使用应用角色 UI 为管理员和一般用户创建角色。
在访问将用户和组分配给 Microsoft Entra 角色部分时,请执行以下步骤:
请不要遵循将应用角色添加到应用程序并在令牌中接收它们中的任何其他步骤。
使用 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”,请输入 。
准备示例
按照以下步骤准备示例应用:
使用以下命令从 GitHub 克隆该示例应用:
git clone https://github.com/Azure-Samples/liberty-entra-id cd liberty-entra-id git checkout 2024-09-26
如果你看到一条关于处于
detached HEAD
状态的消息,可以放心忽略此消息。 此消息仅表示签出了一个标签。使用以下命令来定义以下环境变量以及之前记下的值:
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。 按照以下步骤获取管理员用户和一般用户的电子邮件地址:
- 至少以云应用程序管理员身份登录到 Microsoft Entra 管理中心。
- 如果你有权访问多个租户,请使用顶部菜单中的“设置”图标 (),通过“目录 + 订阅”菜单切换到你希望在其中注册应用程序的租户。
- 浏览到“标识”“用户”“所有用户”。>>
- 在列表中找到管理员用户并选择它。
- 找到“用户主体名称”字段。
- 使用字段值旁边的复制图标将用户的电子邮件地址保存到剪贴板。 保存该值以供以后使用。
- 要获取一般用户的电子邮件地址,请按照相同的步骤操作。
使用创建用户时设置的管理员用户和一般用户的密码。
练习应用的功能
按照以下步骤练习功能:
选择“以用户身份登录”链接。 使用之前创建的一般用户登录。 登录后,Microsoft Entra ID 会重定向到配置文件页面,在这里可以看到名称和角色。
如果这是第一次登录,系统会提示更新密码。 按照说明更新密码。
如果系统提示“你的组织需要其他安全信息。请按照提示下载并设置 Microsoft Authenticator 应用程序”,则可以选择“稍后询问”继续测试。
如果系统提示“请求的权限”,请查看应用程序请求的权限。 选择“接受”以继续测试。
选择“注销”,从应用注销。 注销后,会重定向到欢迎页面。
选择“以管理员身份登录”链接。 Microsoft Entra ID 会重定向到登录页面。 使用之前创建的管理员用户登录。 登录后,Microsoft Entra ID 会重定向到类似的配置文件页面,但具有不同的角色
admin
。再次注销,然后尝试使用之前创建的一般用户以管理员身份登录。 应该会出现一条错误消息,因为一般用户没有
admin
角色。
清理资源
本文并未指导在 Azure 上部署应用。 尽管有 Microsoft Entra ID 资源,但没有应用可清理的 Azure 资源。 若要在 Azure 上部署应用,可以遵循下一部分中的指导。
完成此示例应用的资源后,按照以下步骤清理 Microsoft Entra ID 资源。 删除未使用的 Microsoft Entra ID 资源是一种重要的安全最佳做法。
- 按照“删除在 Microsoft 标识平台注册的应用程序”中的步骤删除创建的应用注册。 只需按照删除组织编写的应用程序部分中的步骤进行操作即可。
- 删除应用注册的行为也应删除企业应用程序。 有关删除企业应用程序的详细信息,请参阅删除企业应用程序。
- 按照如何创建、邀请和删除用户中的步骤删除所创建的用户。
后续步骤
在本快速入门中,将使用 OIDC 保护采用 Microsoft Entra ID 的 WebSphere Liberty/Open Liberty 应用程序。 有关详细信息,请浏览以下资源:
- 在 Azure 容器应用上使用 Open Liberty 或 WebSphere Liberty 部署 Java 应用程序。
- 在 Azure Red Hat OpenShift 上部署 WebSphere Liberty 和 Open Liberty
- 在 Azure Kubernetes Service (AKS) 群集上使用 Open Liberty 或 WebSphere Liberty 部署 Java 应用程序
- 使用 Microsoft Entra ID 进行 OpenID Connect 身份验证
- Microsoft 标识平台和 OAuth 2.0 授权代码流
- 通过社交媒体提供程序对用户进行身份验证
- 社交媒体登录 1.0
- OpenID Connect 客户端 1.0
- 什么是 OpenID Connect
- 编程安全策略配置
- 如何使用 Jakarta EE 保护 RESTful Web 服务
- Jakarta 表达式语言