Protect a web application by using OpenID Connect (OIDC) authorization code flow

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

Discover how to secure application HTTP endpoints by using the Quarkus OpenID Connect (OIDC) authorization code flow mechanism with the Quarkus OIDC extension, providing robust authentication and authorization.

要了解如何将众所周知的社交提供商(例如 Apple、Facebook、GitHub、Google、Mastodon、Microsoft、Spotify、Twitch 和 X(以前的 Twitter)与 Quarkus OIDC 配合使用,请参见 Configuring well-known OpenID Connect providers。另外请参见 Authentication mechanisms in Quarkus

To learn about how well-known social providers such as Apple, Facebook, GitHub, Google, Mastodon, Microsoft, Spotify, Twitch, and X (formerly Twitter) can be used with Quarkus OIDC, see Configuring well-known OpenID Connect providers. See also, Authentication mechanisms in Quarkus.

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

If you want to protect your service applications by using OIDC Bearer token authentication, see OIDC Bearer token authentication.

Prerequisites

Unresolved directive in security-oidc-code-flow-authentication-tutorial.adoc - include::{includes}/prerequisites.adoc[]

Architecture

在此示例中,我们构建了一个具有单个页面的简单 web 应用程序:

In this example, we build a simple web application with a single page:

  • /index.html

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

This page is protected, and only authenticated users can access it.

Solution

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

Follow the instructions in the next sections and create the application step by step. Alternatively, you can go right to the completed example.

通过运行 git clone {quickstarts-clone-url} 命令克隆 Git 存储库。或者下载一个 {quickstarts-archive-url}[存档]。

Clone the Git repository by running the git clone {quickstarts-clone-url} command. Alternatively, download an {quickstarts-archive-url}[archive].

该解决方案位于 security-openid-connect-web-authentication-quickstart directory

The solution is located in the security-openid-connect-web-authentication-quickstart directory.

Create the Maven project

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

First, we need a new project. Create a new project by running the following command:

Unresolved directive in security-oidc-code-flow-authentication-tutorial.adoc - include::{includes}/devtools/create-app.adoc[]

如果你的 Quarkus 项目已经配置好,你可以通过在项目基础目录中运行以下命令将 oidc 扩展名添加到项目:

If you already have your Quarkus project configured, you can add the oidc extension to your project by running the following command in your project base directory:

Unresolved directive in security-oidc-code-flow-authentication-tutorial.adoc - include::{includes}/devtools/extension-add.adoc[]

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

This adds the following dependency to your build file:

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

Write the application

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

Let’s write a simple Jakarta REST resource that has all the tokens returned in the authorization code grant response injected:

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 声明,并返回一个刷新令牌可用性状态。

This endpoint has ID, access, and refresh tokens injected. It returns a preferred_username claim from the ID token, a scope claim from the access token, and a refresh token availability status.

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

You only need to inject the tokens if the endpoint needs to use the ID token to interact with the currently authenticated user or use the access token to access a downstream service on behalf of this user.

有关更多信息,请参阅参考指南的 Access ID and Access Tokens 部分。

For more information, see the Access ID and Access Tokens section of the reference guide.

Configure the application

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

The OIDC extension allows you to define the configuration by using the application.properties file in the src/main/resources directory.

quarkus.oidc.auth-server-url=http://localhost: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

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

This is the simplest configuration you can have when enabling authentication to your application.

quarkus.oidc.client-id 属性引用 OIDC 提供者发出的 client_id,而 quarkus.oidc.credentials.secret 属性设置客户端密钥。

The quarkus.oidc.client-id property references the client_id issued by the OIDC provider, and the quarkus.oidc.credentials.secret property sets the client secret.

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

The quarkus.oidc.application-type property is set to web-app to tell Quarkus that you want to enable the OIDC authorization code flow so that your users are redirected to the OIDC provider to authenticate.

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

Finally, the quarkus.http.auth.permission.authenticated permission is set to tell Quarkus about the paths you want to protect. In this case, all paths are protected by a policy that ensures only authenticated users can access them. For more information, see Security Authorization Guide.

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

When you do not configure a client secret with quarkus.oidc.credentials.secret, it is recommended to configure 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 来禁用加密。但是,您应该只在开发环境中禁用密钥加密。

The quarkus.oidc.token-state-manager.encryption-secret enables the default token state manager to encrypt the user tokens in a browser cookie. If this key is not defined, and the quarkus.oidc.credentials.secret fallback is not configured, Quarkus uses a random key. A random key causes existing logins to be invalidated either on application restart or in environment with multiple instances of your application. Alternatively, encryption can also be disabled by setting quarkus.oidc.token-state-manager.encryption-required to false. However, you should disable secret encryption in development environments only.

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

The encryption secret is recommended to be 32 chars long. For example, quarkus.oidc.token-state-manager.encryption-secret=AyM1SysPpbyDfgZld3umj1qzKObwVMk

Start and configure the Keycloak server

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

To start a Keycloak server, use Docker and run the following command:

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

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

where keycloak.version is set to 25.0.2 or later.

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

You can access your Keycloak Server at localhost:8180.

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

To access the Keycloak Administration Console, log in as the admin user. The username and password are both admin.

要创建新的领域,导入 realm configuration file。有关详细信息,请参阅 Keycloak 文档,了解如何 create and configure a new realm

To create a new realm, import the realm configuration file. For more information, see the Keycloak documentation about how to create and configure a new realm.

Run the application in dev and JVM modes

要以 dev 模式运行应用程序,请使用:

To run the application in dev mode, use:

Unresolved directive in security-oidc-code-flow-authentication-tutorial.adoc - include::{includes}/devtools/dev.adoc[]

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

After exploring the application in dev mode, you can run it as a standard Java application.

首先,对其进行编译:

First, compile it:

Unresolved directive in security-oidc-code-flow-authentication-tutorial.adoc - include::{includes}/devtools/build.adoc[]

然后,运行它:

Then, run it:

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

Run the application in Native mode

可以将此相同演示编译为本机代码。无需任何修改。

This same demo can be compiled into native code. No modifications are required.

这意味着您无需在生产环境中安装 JVM,因为运行时技术包含在生成的可执行文件中,并经过优化,可使用最少资源运行。

This implies that you no longer need to install a JVM on your production environment, as the runtime technology is included in the produced binary and optimized to run with minimal resources.

编译需要更长时间,因此默认情况下此步骤已关闭。您可以通过启用本机构建来重新构建:

Compilation takes longer, so this step is turned off by default. You can build again by enabling the native build:

Unresolved directive in security-oidc-code-flow-authentication-tutorial.adoc - include::{includes}/devtools/build-native.adoc[]

一段时间后,您可以直接运行此二进制文件:

After a while, you can run this binary directly:

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

Test the application

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

To test the application, open your browser and access the following URL:

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

If everything works as expected, you are redirected to the Keycloak server to authenticate.

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

To authenticate to the application, enter the following credentials at the Keycloak login page:

  • Username: alice

  • Password: alice

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

After clicking the Login button, you are redirected back to the application, and a session cookie will be created.

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

The session for this demo is valid for a short period of time and, on every page refresh, you will be asked to re-authenticate. For information about how to increase the session timeouts, see the Keycloak session timeout documentation. For example, you can access the Keycloak Admin console directly from the dev UI by clicking the Keycloak Admin link if you use Dev Services for Keycloak in dev mode:

dev ui oidc keycloak card

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

For more information about writing the integration tests that depend on Dev Services for Keycloak, see the Dev Services for Keycloak section.

Summary

您已经了解如何设置和使用 OIDC 授权代码流机制来保护和测试应用程序 HTTP 端点。完成本教程后,浏览 OIDC Bearer token authenticationother authentication mechanisms

You have learned how to set up and use the OIDC authorization code flow mechanism to protect and test application HTTP endpoints. After you have completed this tutorial, explore OIDC Bearer token authentication and other authentication mechanisms.