编辑此页面

使用 OpenID Connect (OIDC) 授权码流保护 Web 应用程序

了解如何使用 Quarkus OpenID Connect (OIDC) 扩展的 OIDC 授权码流程机制来保护应用程序 HTTP 端点,从而提供强大的身份验证和授权。

要了解如何将 Apple、Facebook、GitHub、Google、Mastodon、Microsoft、Spotify、Twitch 和 X(以前的 Twitter)等知名社交提供商与 Quarkus OIDC 一起使用,请参阅配置知名的 OpenID Connect 提供商。 另请参阅Quarkus 中的身份验证机制

如果您想使用 OIDC Bearer 令牌身份验证来保护您的服务应用程序,请参阅OIDC Bearer 令牌身份验证

先决条件

要完成本指南,您需要

  • 大约 15 分钟

  • 一个 IDE

  • 已安装 JDK 17+ 并正确配置了 JAVA_HOME

  • Apache Maven 3.9.9

  • 一个正常工作的容器运行时(Docker 或 Podman

  • 如果您想使用它,可以选择 Quarkus CLI

  • 如果您想构建本机可执行文件(或者如果您使用本机容器构建,则为 Docker),可以选择安装 Mandrel 或 GraalVM 并进行适当的配置

架构

在此示例中,我们构建一个简单的 Web 应用程序,其中包含一个页面

  • /index.html

此页面受到保护,只有经过身份验证的用户才能访问它。

解决方案

请按照以下章节中的说明逐步创建应用程序。或者,您可以直接转到已完成的示例。

运行 git clone https://github.com/quarkusio/quarkus-quickstarts.git 命令克隆 Git 存储库。 或者,下载存档

解决方案位于 security-openid-connect-web-authentication-quickstart 目录中。

1. 创建 Maven 项目

首先,我们需要一个新项目。 运行以下命令创建一个新项目

CLI
quarkus create app org.acme:security-openid-connect-web-authentication-quickstart \
    --extension='rest,oidc' \
    --no-code
cd security-openid-connect-web-authentication-quickstart

要创建 Gradle 项目,请添加 --gradle--gradle-kotlin-dsl 选项。

有关如何安装和使用 Quarkus CLI 的更多信息,请参阅 Quarkus CLI 指南。

Maven
mvn io.quarkus.platform:quarkus-maven-plugin:3.24.4:create \
    -DprojectGroupId=org.acme \
    -DprojectArtifactId=security-openid-connect-web-authentication-quickstart \
    -Dextensions='rest,oidc' \
    -DnoCode
cd security-openid-connect-web-authentication-quickstart

要创建 Gradle 项目,请添加 -DbuildTool=gradle-DbuildTool=gradle-kotlin-dsl 选项。

对于 Windows 用户

  • 如果使用 cmd,(不要使用反斜杠 \ 并将所有内容放在同一行上)

  • 如果使用 Powershell,请将 -D 参数括在双引号中,例如 "-DprojectArtifactId=security-openid-connect-web-authentication-quickstart"

如果您已经配置了 Quarkus 项目,则可以通过在项目基本目录中运行以下命令将 oidc 扩展添加到您的项目中

CLI
quarkus extension add oidc
Maven
./mvnw quarkus:add-extension -Dextensions='oidc'
Gradle
./gradlew addExtension --extensions='oidc'

这会将以下依赖项添加到您的构建文件中

pom.xml
<dependency>
   <groupId>io.quarkus</groupId>
   <artifactId>quarkus-oidc</artifactId>
</dependency>
build.gradle
implementation("io.quarkus:quarkus-oidc")

2. 编写应用程序

让我们编写一个简单的 Jakarta REST 资源,该资源具有在授权码授予响应中返回的所有令牌注入

package org.acme.security.openid.connect.web.authentication;

import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;

import org.eclipse.microprofile.jwt.Claims;
import org.eclipse.microprofile.jwt.JsonWebToken;

import io.quarkus.oidc.IdToken;
import io.quarkus.oidc.RefreshToken;

@Path("/tokens")
public class TokenResource {

   /**
    * Injection point for the ID token issued by the OpenID Connect provider
    */
   @Inject
   @IdToken
   JsonWebToken idToken;

   /**
    * Injection point for the access token issued by the OpenID Connect provider
    */
   @Inject
   JsonWebToken accessToken;

   /**
    * Injection point for the refresh token issued by the OpenID Connect provider
    */
   @Inject
   RefreshToken refreshToken;

   /**
    * Returns the tokens available to the application.
    * This endpoint exists only for demonstration purposes.
    * Do not expose these tokens in a real application.
    *
    * @return an HTML page containing the tokens available to the application.
    */
   @GET
   @Produces("text/html")
   public String getTokens() {
       StringBuilder response = new StringBuilder().append("<html>")
               .append("<body>")
               .append("<ul>");


       Object userName = this.idToken.getClaim(Claims.preferred_username);

       if (userName != null) {
           response.append("<li>username: ").append(userName.toString()).append("</li>");
       }

       Object scopes = this.accessToken.getClaim("scope");

       if (scopes != null) {
           response.append("<li>scopes: ").append(scopes.toString()).append("</li>");
       }

       response.append("<li>refresh_token: ").append(refreshToken.getToken() != null).append("</li>");

       return response.append("</ul>").append("</body>").append("</html>").toString();
   }
}

此端点注入了 ID、访问和刷新令牌。 它从 ID 令牌返回 preferred_username 声明,从访问令牌返回 scope 声明,以及刷新令牌可用性状态。

只有在端点需要使用 ID 令牌与当前经过身份验证的用户交互,或者使用访问令牌代表此用户访问下游服务时,才需要注入令牌。

有关更多信息,请参阅参考指南的访问 ID 和访问令牌部分。

3. 配置应用程序

OIDC 扩展允许您使用 src/main/resources 目录中的 application.properties 文件定义配置。

%prod.quarkus.oidc.auth-server-url=https://:8180/realms/quarkus
quarkus.oidc.client-id=frontend
quarkus.oidc.credentials.secret=secret
quarkus.oidc.application-type=web-app
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated

这是在启用应用程序身份验证时可以拥有的最简单的配置。

quarkus.oidc.client-id 属性引用 OIDC 提供程序颁发的 client_idquarkus.oidc.credentials.secret 属性设置客户端密码。

quarkus.oidc.application-type 属性设置为 web-app,以告知 Quarkus 您要启用 OIDC 授权码流程,以便将用户重定向到 OIDC 提供程序进行身份验证。

最后,quarkus.http.auth.permission.authenticated 权限已设置,以告知 Quarkus 您要保护的路径。 在这种情况下,所有路径都受到策略的保护,该策略确保只有 authenticated 用户才能访问它们。 有关更多信息,请参阅安全授权指南

当您不使用 quarkus.oidc.credentials.secret 配置客户端密码时,建议配置 quarkus.oidc.token-state-manager.encryption-secret

quarkus.oidc.token-state-manager.encryption-secret 使默认令牌状态管理器能够加密浏览器 Cookie 中的用户令牌。 如果未定义此密钥,并且未配置 quarkus.oidc.credentials.secret 回退,则 Quarkus 将使用随机密钥。 随机密钥会导致现有登录在应用程序重新启动时或在应用程序的多个实例的环境中失效。 或者,也可以通过将 quarkus.oidc.token-state-manager.encryption-required 设置为 false 来禁用加密。 但是,您应该仅在开发环境中禁用密钥加密。

建议加密密钥的长度为 32 个字符。 例如,quarkus.oidc.token-state-manager.encryption-secret=AyM1SysPpbyDfgZld3umj1qzKObwVMk

4. 启动并配置 Keycloak 服务器

要启动 Keycloak 服务器,请使用 Docker 并运行以下命令

docker run --name keycloak -e KC_BOOTSTRAP_ADMIN_USERNAME=admin -e KC_BOOTSTRAP_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev

其中 keycloak.version 设置为 26.2.4 或更高版本。

您可以在 localhost:8180 访问您的 Keycloak 服务器。

要访问 Keycloak 管理控制台,请以 admin 用户身份登录。 用户名和密码均为 admin

要创建新领域,请导入领域配置文件。 有关更多信息,请参阅 Keycloak 文档,了解如何创建和配置新领域

5. 在开发和 JVM 模式下运行应用程序

要在开发模式下运行应用程序,请使用

CLI
quarkus dev
Maven
./mvnw quarkus:dev
Gradle
./gradlew --console=plain quarkusDev

在开发模式下探索完应用程序后,您可以将其作为标准的 Java 应用程序运行。

首先,编译它

CLI
quarkus build
Maven
./mvnw install
Gradle
./gradlew build

然后,运行它

java -jar target/quarkus-app/quarkus-run.jar

6. 在 Native 模式下运行应用程序

此演示也可以编译为本机代码。 无需修改。

这意味着您不再需要在生产环境中安装 JVM,因为运行时技术包含在生成的二进制文件中,并且经过优化以最小的资源运行。

编译需要更长的时间,因此默认情况下禁用此步骤。 您可以通过启用本机构建再次构建

CLI
quarkus build --native
Maven
./mvnw install -Dnative
Gradle
./gradlew build -Dquarkus.native.enabled=true

稍后,您可以直接运行此二进制文件

./target/security-openid-connect-web-authentication-quickstart-runner

7. 测试应用程序

要测试应用程序,请打开浏览器并访问以下 URL

如果一切按预期工作,您将被重定向到 Keycloak 服务器进行身份验证。

要对应用程序进行身份验证,请在 Keycloak 登录页面上输入以下凭据

  • 用户名:alice

  • 密码:alice

单击 Login 按钮后,您将被重定向回应用程序,并且将创建一个会话 Cookie。

此演示的会话有效期很短,并且每次页面刷新时,您都会被要求重新进行身份验证。 有关如何增加会话超时的信息,请参阅 Keycloak 会话超时文档。 例如,如果您在开发模式下使用 Keycloak 的开发服务,则可以通过单击 Keycloak Admin 链接直接从开发 UI 访问 Keycloak 管理控制台

Dev UI OpenID Connect Card

有关编写依赖于 Dev Services for Keycloak 的集成测试的更多信息,请参阅 Dev Services for Keycloak 部分。

总结

您已经学习了如何设置和使用 OIDC 授权码流程机制来保护和测试应用程序 HTTP 端点。 完成本教程后,请探索 OIDC Bearer 令牌身份验证其他身份验证机制

相关内容