MicroProfile JSON Web 令牌(JWT)身份验证


Red Hat build of Quarkus 3.20

Red Hat Customer Content Services

摘要

本指南主要探索 JSON Web 令牌(JWT)安全性的基本内容,专注于安全令牌生成、存储和验证机制。它在应用架构中被分成 JWT 集成,并提供实用步骤,为基于令牌的身份验证系统实施安全构建和部署管道。

向红帽构建的 Quarkus 文档提供反馈

要报告错误或改进文档,请登录您的红帽 JIRA 帐户并提交问题。如果您没有红帽 JIRA 帐户,系统会提示您创建一个帐户。

流程

  1. 单击以下链接 来创建 ticket
  2. Summary 中输入有关此问题的简单描述。
  3. 描述中提供问题或增强功能的详细描述。请包括有问题的文档 URL。
  4. Submit 创建问题并将其路由到适当的文档团队。

第 1 章 使用 JWT RBAC

本指南介绍了如何将 SmallRye JWT 集成到 Quarkus 应用中,以根据 MicroProfile JWT 规范实施 JSON Web Token (JWT) 安全性。您将了解如何验证 JWT,将它们代表为 MicroProfile JWT org.eclipse.microprofile.jwt.JsonWebToken,以及使用 bearer 令牌授权和基于角色的访问控制来保护 Quarkus HTTP 端点。https://en.wikipedia.org/wiki/Role-based_access_control

注意

Quarkus OpenID Connect (quarkus-oidc)扩展也支持 bearer 令牌授权,并使用 smallrye-jwt 来代表 bearer 令牌作为 JsonWebToken。详情请查看 OIDC Bearer Token Authentication 指南。

如果您的 Quarkus 应用程序需要使用 OIDC 授权代码流验证用户,则必须使用 OpenID Connect 扩展。如需更多信息,请参阅 用于保护 Web 应用程序的 OIDC 代码流机制

1.1. 先决条件

要完成本指南,您需要:

1.2. Quickstart

1.2.1. 解决方案

我们建议您按照后续部分中的说明来逐步创建应用程序步骤。如果您愿意,可以进入已完成的示例。

要访问示例,请克隆 Git 存储库或下载存档:

已完成的解决方案位于 security-jwt-quickstart 目录中

1.2.2. 创建 Maven 项目

首先,使用以下命令创建新项目:

  • 使用 Quarkus CLI:

    quarkus create app org.acme:security-jwt-quickstart \
        --extension='rest-jackson,smallrye-jwt,smallrye-jwt-build' \
        --no-code
    cd security-jwt-quickstart
    Copy to clipboard

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

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

  • 使用 Maven:

    mvn com.redhat.quarkus.platform:quarkus-maven-plugin:3.20.1:create \
        -DprojectGroupId=org.acme \
        -DprojectArtifactId=security-jwt-quickstart \
        -Dextensions='rest-jackson,smallrye-jwt,smallrye-jwt-build' \
        -DnoCode
    cd security-jwt-quickstart
    Copy to clipboard

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

对于 Windows 用户:

  • 如果使用 cmd,(不要使用反向斜杠 \ 并将所有内容放在同一行中)
  • 如果使用 Powershell,则双引号中的 wrap -D 参数,如 "-DprojectArtifactId=security-jwt-quickstart"

此命令生成 Maven 项目并导入 smallrye-jwt 扩展,其包含 MicroProfile JWT RBAC 支持。

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

  • 使用 Quarkus CLI:

    quarkus extension add smallrye-jwt,smallrye-jwt-build
    Copy to clipboard
  • 使用 Maven:

    ./mvnw quarkus:add-extension -Dextensions='smallrye-jwt,smallrye-jwt-build'
    Copy to clipboard
  • 使用 Gradle:

    ./gradlew addExtension --extensions='smallrye-jwt,smallrye-jwt-build'
    Copy to clipboard

这个命令在构建文件中添加以下依赖项:

  • 使用 Maven:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-smallrye-jwt</artifactId>
    </dependency>
    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-smallrye-jwt-build</artifactId>
    </dependency>
    Copy to clipboard
  • 使用 Gradle:

    implementation("io.quarkus:quarkus-smallrye-jwt")
    implementation("io.quarkus:quarkus-smallrye-jwt-build")
    Copy to clipboard

1.2.3. 检查 Jakarta REST 资源

src/main/java/org/acme/security/jwt/TokenSecuredResource.java 中创建一个 REST 端点,其内容如下:

REST 端点 V1

package org.acme.security.jwt;

import jakarta.annotation.security.PermitAll;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;

import org.eclipse.microprofile.jwt.JsonWebToken;

@Path("/secured")
public class TokenSecuredResource {

    @Inject
    JsonWebToken jwt; 1

    @GET
    @Path("permit-all")
    @PermitAll 2
    @Produces(MediaType.TEXT_PLAIN)
    public String hello(@Context SecurityContext ctx) {
        return getResponseString(ctx); 3
    }

    private String getResponseString(SecurityContext ctx) {
        String name;
        if (ctx.getUserPrincipal() == null) { 4
            name = "anonymous";
        } else if (!ctx.getUserPrincipal().getName().equals(jwt.getName())) { 5
            throw new InternalServerErrorException("Principal and JsonWebToken names do not match");
        } else {
            name = ctx.getUserPrincipal().getName(); 6
        }
        return String.format("hello %s,"
            + " isHttps: %s,"
            + " authScheme: %s,"
            + " hasJWT: %s",
            name, ctx.isSecure(), ctx.getAuthenticationScheme(), hasJwt()); 7
    }

    private boolean hasJwt() {
        return jwt.getClaimNames() != null;
    }
}
Copy to clipboard

1
JsonWebToken 接口被注入,提供对与当前经过身份验证的用户关联的声明的访问。这个接口扩展了 java.security.Principal
2
@PermitAll 是标准的 Jakarta 安全注释。表示给定端点可以被所有调用者访问,无论是否通过身份验证。
3
Jakarta REST SecurityContext 被注入,以检查请求的安全状态。getResponseString () 函数生成响应。
4
通过检查请求用户/调用者 Principal 是否针对 null 检查调用是否不安全。
5
确保 PrincipalJsonWebToken 中的名称与 JsonWebToken 匹配,因为 JsonWebToken 代表当前的 主体
6
检索 Principal 的名称。
7
构建包含调用者名称的 isSecure ()getAuthenticationScheme () 状态的响应,以及是否注入了非null JsonWebToken

1.2.4. 在 dev 模式下运行应用程序

现在,您可以使用以下命令以 dev 模式运行应用程序:

  • 使用 Quarkus CLI:

    quarkus dev
    Copy to clipboard
  • 使用 Maven:

    ./mvnw quarkus:dev
    Copy to clipboard
  • 使用 Gradle:

    ./gradlew --console=plain quarkusDev
    Copy to clipboard

然后,您应该看到类似以下示例的输出:

quarkus:dev output

[INFO] Scanning for projects...
[INFO]
[INFO] ----------------------< org.acme:security-jwt-quickstart >-----------------------
[INFO] Building security-jwt-quickstart 1.0.0-SNAPSHOT
[INFO] --------------------------------[ jar ]---------------------------------
...
Listening for transport dt_socket at address: 5005
2020-07-15 16:09:50,883 INFO  [io.quarkus] (Quarkus Main Thread) security-jwt-quickstart 1.0.0-SNAPSHOT on JVM (powered by Quarkus 999-SNAPSHOT) started in 1.073s. Listening on: http://0.0.0.0:8080
2020-07-15 16:09:50,885 INFO  [io.quarkus] (Quarkus Main Thread) Profile dev activated. Live Coding activated.
2020-07-15 16:09:50,885 INFO  [io.quarkus] (Quarkus Main Thread) Installed features: [cdi, mutiny, rest, rest-jackson, security, smallrye-context-propagation, smallrye-jwt, vertx, vertx-web]
Copy to clipboard

现在,REST 端点正在运行,您可以使用命令行工具(如 curl)访问它:

/secured/permit-allcurl 命令

$ curl http://127.0.0.1:8080/secured/permit-all; echo
Copy to clipboard

这个命令返回以下响应:

hello anonymous, isHttps: false, authScheme: null, hasJWT: false
Copy to clipboard

您没有在我们的请求中提供任何 JWT,因此您不会预期端点查看任何安全状态,并且响应与其一致:

  • 用户名是 匿名的。
  • isHttpsfalse,因为不使用 https
  • authSchemenull
  • 的JWTfalse

使用 Ctrl-C 停止 Quarkus 服务器。

现在,我们来保证.查看新端点方法 helloRolesAllowed,如下所示:

REST 端点 V2

package org.acme.security.jwt;

import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;

import org.eclipse.microprofile.jwt.JsonWebToken;

@Path("/secured")
public class TokenSecuredResource {

    @Inject
    JsonWebToken jwt; 1

    @GET
    @Path("permit-all")
    @PermitAll
    @Produces(MediaType.TEXT_PLAIN)
    public String hello(@Context SecurityContext ctx) {
        return getResponseString(ctx);
    }

    @GET
    @Path("roles-allowed") 2
    @RolesAllowed({ "User", "Admin" }) 3
    @Produces(MediaType.TEXT_PLAIN)
    public String helloRolesAllowed(@Context SecurityContext ctx) {
        return getResponseString(ctx) + ", birthdate: " + jwt.getClaim("birthdate").toString(); 4
    }

    private String getResponseString(SecurityContext ctx) {
        String name;
        if (ctx.getUserPrincipal() == null) {
            name = "anonymous";
        } else if (!ctx.getUserPrincipal().getName().equals(jwt.getName())) {
            throw new InternalServerErrorException("Principal and JsonWebToken names do not match");
        } else {
            name = ctx.getUserPrincipal().getName();
        }
        return String.format("hello %s,"
            + " isHttps: %s,"
            + " authScheme: %s,"
            + " hasJWT: %s",
            name, ctx.isSecure(), ctx.getAuthenticationScheme(), hasJwt());
    }

    private boolean hasJwt() {
        return jwt.getClaimNames() != null;
    }
}
Copy to clipboard

1
注入 JsonWebToken 以访问 JWT 中的声明。
2
此端点通过 /secured/roles-allowed 公开。
3
@RolesAllowed 注释限制对具有"User"或"Admin"角色的用户的访问。
4
响应构建方式与 hello 方法相似,添加了直接从注入的 JsonWebToken 检索的 birthdate 声明。

在添加了 TokenSecuredResource 后,重新运行 ./mvnw quarkus:dev 命令,然后尝试 curl -v http://127.0.0.1:8080/secured/roles-allowed; echo 以尝试访问新端点。

您的输出应如下所示:

/secured/roles-allowedcurl 命令

$ curl -v http://127.0.0.1:8080/secured/roles-allowed; echo
Copy to clipboard

这个命令返回以下响应:

*   Trying 127.0.0.1...
* TCP_NODELAY set
* Connected to 127.0.0.1 (127.0.0.1) port 8080 (#0)
> GET /secured/roles-allowed HTTP/1.1
> Host: 127.0.0.1:8080
> User-Agent: curl/7.54.0
> Accept: */*
>
< HTTP/1.1 401 Unauthorized
< Connection: keep-alive
< Content-Type: text/html;charset=UTF-8
< Content-Length: 14
< Date: Sun, 03 Mar 2019 16:32:34 GMT
<
* Connection #0 to host 127.0.0.1 left intact
Copy to clipboard

卓越的.您没有在请求中提供 JWT,因此正确拒绝对端点的访问。相反,您会收到 HTTP 401 Unauthorized 错误。

若要访问端点,您必须获取并在请求中包含有效的 JWT。这涉及两个步骤:

  1. 使用必要信息配置 SmallRye JWT 扩展以验证 JWT。
  2. 使用适当的声明生成 JWT 以匹配配置。

1.2.5. 配置 SmallRye JWT 扩展安全信息

使用以下内容创建 security-jwt-quickstart/src/main/resources/application.properties

TokenSecuredResource的应用程序属性

mp.jwt.verify.publickey.location=publicKey.pem 1
mp.jwt.verify.issuer=https://example.com/issuer 2

quarkus.native.resources.includes=publicKey.pem 3
Copy to clipboard

1
指定 classpath 上公钥文件 publicKey.pem 的位置。请参阅为 添加此密钥 添加公钥。
2
将预期的签发者定义为 https://example.com/issuer
3
确保 publicKey.pem 文件作为原生可执行文件中的资源包含。

1.2.6. 添加公钥

JWT 规范定义 可以使用的 JWT 的各种安全性级别。MicroProfile JWT RBAC 规范需要使用 RSA-256 签名算法签名的 JWT。这反过来需要一个 RSA 公钥对。在 REST 端点服务器端,您需要配置 RSA 公钥的位置,以验证与请求一起发送的 JWT。mp.jwt.verify.publickey.location=publicKey.pem 设置预期之前配置的公钥为 publicKey.pem。要达到此目的,请将以下内容复制到 security-jwt-quickstart/src/main/resources/publicKey.pem 文件中。

RSA 公钥 PEM 内容

-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq
Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR
TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e
UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9
AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn
sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x
nQIDAQAB
-----END PUBLIC KEY-----
Copy to clipboard

1.2.7. 生成 JWT

通常,从 Keycloak 等身份管理器获取 JWT。但是,对于此快速入门,您可以使用 smallrye-jwt 提供的 JWT 生成 API 自行生成。如需更多信息,请参阅使用 SmallRye JWT 生成 JWT 令牌

从以下列表中获取代码,并将它放入 security-jwt-quickstart/src/test/java/org/acme/security/jwt/GenerateToken.java 中:

GenerateToken 主驱动程序类

package org.acme.security.jwt;

import java.util.Arrays;
import java.util.HashSet;

import org.eclipse.microprofile.jwt.Claims;
import io.smallrye.jwt.build.Jwt;

/**
 * A utility class to generate and print a JWT token string to stdout.
 */
public class GenerateToken {

    /**
     * Generates and prints a JWT token.
     */
    public static void main(String[] args) {
        String token = Jwt.issuer("https://example.com/issuer") 1
                .upn("jdoe@quarkus.io") 2
                .groups(new HashSet<>(Arrays.asList("User", "Admin"))) 3
                .claim(Claims.birthdate.name(), "2001-07-13") 4
                .sign();

        System.out.println(token);
        System.exit(0);
    }
}
Copy to clipboard

1
在 JWT 中设置 iss (issuer)声明。这个值必须与服务器端 mp.jwt.verify.issuer 配置匹配,以便令牌被视为有效。
2
指定 upn (User Principal Name)声明,MicroProfile JWT RBAC 规范将它定义为识别容器安全 API 中 Principal 的首选声明。
3
定义 groups 声明,它提供组成员资格和分配给 JWT bearer 的顶级角色。
4
添加 birthdate 声明。由于这被视为敏感信息,因此请考虑加密声明,如 使用 SmallRye JWT 生成 JWT 令牌 中所述。

请注意,为此代码正常工作,您需要与您在 TokenSecuredResource 应用程序中的公钥对应的 RSA 私钥的内容。取以下 PEM 内容并将其放入 security-jwt-quickstart/src/test/resources/privateKey.pem 中:

RSA 私钥 PEM 内容

-----BEGIN PRIVATE KEY-----
MIIEvQIBADANBgkqhkiG9w0BAQEFAASCBKcwggSjAgEAAoIBAQCWK8UjyoHgPTLa
PLQJ8SoXLLjpHSjtLxMqmzHnFscqhTVVaDpCRCb6e3Ii/WniQTWw8RA7vf4djz4H
OzvlfBFNgvUGZHXDwnmGaNVaNzpHYFMEYBhE8VGGiveSkzqeLZI+Y02G6sQAfDtN
qqzM/l5QX8X34oQFaTBW1r49nftvCpITiwJvWyhkWtXP9RP8sXi1im5Vi3dhupOh
nelk5n0BfajUYIbfHA6ORzjHRbt7NtBl0L2J+0/FUdHyKs6KMlFGNw8O0Dq88qnM
uXoLJiewhg9332W3DFMeOveel+//cvDnRsCRtPgd4sXFPHh+UShkso7+DRsChXa6
oGGQD3GdAgMBAAECggEAAjfTSZwMHwvIXIDZB+yP+pemg4ryt84iMlbofclQV8hv
6TsI4UGwcbKxFOM5VSYxbNOisb80qasb929gixsyBjsQ8284bhPJR7r0q8h1C+jY
URA6S4pk8d/LmFakXwG9Tz6YPo3pJziuh48lzkFTk0xW2Dp4SLwtAptZY/+ZXyJ6
96QXDrZKSSM99Jh9s7a0ST66WoxSS0UC51ak+Keb0KJ1jz4bIJ2C3r4rYlSu4hHB
Y73GfkWORtQuyUDa9yDOem0/z0nr6pp+pBSXPLHADsqvZiIhxD/O0Xk5I6/zVHB3
zuoQqLERk0WvA8FXz2o8AYwcQRY2g30eX9kU4uDQAQKBgQDmf7KGImUGitsEPepF
KH5yLWYWqghHx6wfV+fdbBxoqn9WlwcQ7JbynIiVx8MX8/1lLCCe8v41ypu/eLtP
iY1ev2IKdrUStvYRSsFigRkuPHUo1ajsGHQd+ucTDf58mn7kRLW1JGMeGxo/t32B
m96Af6AiPWPEJuVfgGV0iwg+HQKBgQCmyPzL9M2rhYZn1AozRUguvlpmJHU2DpqS
34Q+7x2Ghf7MgBUhqE0t3FAOxEC7IYBwHmeYOvFR8ZkVRKNF4gbnF9RtLdz0DMEG
5qsMnvJUSQbNB1yVjUCnDAtElqiFRlQ/k0LgYkjKDY7LfciZl9uJRl0OSYeX/qG2
tRW09tOpgQKBgBSGkpM3RN/MRayfBtmZvYjVWh3yjkI2GbHA1jj1g6IebLB9SnfL
WbXJErCj1U+wvoPf5hfBc7m+jRgD3Eo86YXibQyZfY5pFIh9q7Ll5CQl5hj4zc4Y
b16sFR+xQ1Q9Pcd+BuBWmSz5JOE/qcF869dthgkGhnfVLt/OQzqZluZRAoGAXQ09
nT0TkmKIvlza5Af/YbTqEpq8mlBDhTYXPlWCD4+qvMWpBII1rSSBtftgcgca9XLB
MXmRMbqtQeRtg4u7dishZVh1MeP7vbHsNLppUQT9Ol6lFPsd2xUpJDc6BkFat62d
Xjr3iWNPC9E9nhPPdCNBv7reX7q81obpeXFMXgECgYEAmk2Qlus3OV0tfoNRqNpe
Mb0teduf2+h3xaI1XDIzPVtZF35ELY/RkAHlmWRT4PCdR0zXDidE67L6XdJyecSt
FdOUH8z5qUraVVebRFvJqf/oGsXc4+ex1ZKUTbY0wqY1y9E39yvB3MaTmZFuuqk8
f3cg+fr8aou7pr9SHhJlZCU=
-----END PRIVATE KEY-----
Copy to clipboard

之后,您要配置 smallrye.jwt.sign.key.location 属性来指定私钥的位置。

使用 OpenSSL 生成密钥

也可以使用 OpenSSL 命令行工具生成公钥和私钥对。

用于生成密钥的 OpenSSL 命令

openssl genrsa -out rsaPrivateKey.pem 2048
openssl rsa -pubout -in rsaPrivateKey.pem -out publicKey.pem
Copy to clipboard

需要额外的步骤来生成私钥并将其转换为 PKCS"8 格式,通常用于安全密钥存储和传输。

用于执行转换的 OpenSSL 命令

openssl pkcs8 -topk8 -nocrypt -inform pem -in rsaPrivateKey.pem -outform pem -out privateKey.pem
Copy to clipboard

您可以使用生成的密钥对而不是这个快速入门中使用的密钥对。

在为 TokenSecuredResource 端点生成 JSON Web Token (JWT)之前,请确保 应用正在运行

接下来,使用以下命令生成 JWT:

JWT 生成输出示例

$ mvn exec:java -Dexec.mainClass=org.acme.security.jwt.GenerateToken -Dexec.classpathScope=test -Dsmallrye.jwt.sign.key.location=privateKey.pem
Copy to clipboard

JWT 字符串是由三个部分组成的 Base64 URL 编码字符串,用 . 字符分隔:

  1. 标头,其中包含令牌的元数据,如签名算法。
  2. 有效负载也称为 "claims",其中包括令牌的声明或数据。
  3. 签名,验证令牌的完整性。

1.2.8. 最后,对 /secured/roles-allowed进行安全访问

现在,让我们使用它来向 /secured/roles-allowed 端点发出安全请求。确保 Quarkus 服务器仍然以 dev 模式运行,然后运行以下命令,确保使用上一步中生成的 JWT 版本:

使用 JWT 进行 /secured/roles-allowedcurl 命令

$ curl -H "Authorization: Bearer eyJraWQ..." http://127.0.0.1:8080/secured/roles-allowed; echo
Copy to clipboard

确保将生成的令牌用作 HTTP Authorization Bearer 方案值。

这个命令返回以下响应:

hello jdoe@quarkus.io, isHttps: false, authScheme: Bearer, hasJWT: true, birthdate: 2001-07-13
Copy to clipboard

成功!现在您有以下内容:

  • 非匿名调用者名称: jdoe@quarkus.io
  • 身份验证方案: Bearer
  • 非null JsonWebToken
  • birthdate 声明值

1.2.9. 使用 JsonWebToken 和声明注入

现在,您可以生成 JWT 以访问我们的安全 REST 端点,让我们看到您可以使用 JsonWebToken 接口和 JWT 声明进行更多的操作。org.eclipse.microprofile.jwt.JsonWebToken 接口扩展了 java.security.Principal 接口,并且是由之前使用的 jakarta.ws.ws.rs.core.SecurityContext SerialgetUserPrincipal () 调用返回的对象类型。这意味着,不使用 CDI 但可以访问 REST 容器 SecurityContext 的代码可以存放调用者 JsonWebToken 接口。

JsonWebToken 接口定义了在底层 JWT 中访问声明的方法。它为 MicroProfile JWT RBAC 规范和 JWT 中可能存在的任意声明提供常见声明的访问权限。

也可以注入所有 JWT 声明。我们使用另一个端点 /secured/roles-allowed-admin 扩展 TokenSecuredResource,该端点使用注入的 birthdate 声明(而不是从 JsonWebToken获取):

package org.acme.security.jwt;

import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.RequestScoped;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.InternalServerErrorException;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.MediaType;
import jakarta.ws.rs.core.SecurityContext;

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

@Path("/secured")
@RequestScoped 1
public class TokenSecuredResource {

    @Inject
    JsonWebToken jwt; 2
    @Inject
    @Claim(standard = Claims.birthdate)
    String birthdate; 3

    @GET
    @Path("permit-all")
    @PermitAll
    @Produces(MediaType.TEXT_PLAIN)
    public String hello(@Context SecurityContext ctx) {
        return getResponseString(ctx);
    }

    @GET
    @Path("roles-allowed")
    @RolesAllowed({ "User", "Admin" })
    @Produces(MediaType.TEXT_PLAIN)
    public String helloRolesAllowed(@Context SecurityContext ctx) {
        return getResponseString(ctx) + ", birthdate: " + jwt.getClaim("birthdate").toString();
    }

    @GET
    @Path("roles-allowed-admin")
    @RolesAllowed("Admin")
    @Produces(MediaType.TEXT_PLAIN)
    public String helloRolesAllowedAdmin(@Context SecurityContext ctx) {
        return getResponseString(ctx) + ", birthdate: " + birthdate; 4
    }

    private String getResponseString(SecurityContext ctx) {
        String name;
        if (ctx.getUserPrincipal() == null) {
            name = "anonymous";
        } else if (!ctx.getUserPrincipal().getName().equals(jwt.getName())) {
            throw new InternalServerErrorException("Principal and JsonWebToken names do not match");
        } else {
            name = ctx.getUserPrincipal().getName();
        }
        return String.format("hello %s,"
            + " isHttps: %s,"
            + " authScheme: %s,"
            + " hasJWT: %s",
            name, ctx.isSecure(), ctx.getAuthenticationScheme(), hasJwt());
    }

    private boolean hasJwt() {
        return jwt.getClaimNames() != null;
    }
}
Copy to clipboard
1
需要 @RequestScoped 范围,才能将 birthdate 声明注入为 String
2
此处注入了 JsonWebToken,为所有声明和 JWT 相关的信息提供访问权限。
3
birthdate 声明被注入为 String。这重点介绍了 @RequestScoped 范围必须的原因。
4
注入的 birthdate 声明直接用于构造响应。

现在再次生成令牌并运行:

$ curl -H "Authorization: Bearer eyJraWQ..." http://127.0.0.1:8080/secured/roles-allowed-admin; echo
Copy to clipboard

确保将生成的令牌用作 HTTP Authorization Bearer 方案值。

这个命令返回以下响应:

hello jdoe@quarkus.io, isHttps: false, authScheme: Bearer, hasJWT: true, birthdate: 2001-07-13
Copy to clipboard

1.2.10. 在 JVM 模式下运行应用程序

您可以将应用程序作为标准 Java 应用程序运行。

  1. 编译应用程序:

    • 使用 Quarkus CLI:

      quarkus build
      Copy to clipboard
    • 使用 Maven:

      ./mvnw install
      Copy to clipboard
    • 使用 Gradle:

      ./gradlew build
      Copy to clipboard
  2. 运行应用程序:

    java -jar target/quarkus-app/quarkus-run.jar
    Copy to clipboard

1.2.11. 以原生模式运行应用程序

您可以在不进行任何修改的情况下,将相同的演示编译为原生模式。这意味着您不再需要在生产环境中安装 JVM。运行时技术包含在生成的二进制中,并经过优化,以便以最少的资源运行。

编译时间需要一些时间,因此默认禁用此步骤。

  1. 通过启用 原生 配置集来再次构建应用程序:

    • 使用 Quarkus CLI:

      quarkus build --native
      Copy to clipboard
    • 使用 Maven:

      ./mvnw install -Dnative
      Copy to clipboard
    • 使用 Gradle:

      ./gradlew build -Dquarkus.native.enabled=true
      Copy to clipboard
  2. 直接运行以下二进制文件:

    ./target/security-jwt-quickstart-1.0.0-SNAPSHOT-runner
    Copy to clipboard

1.2.12. 探索解决方案

security-jwt-quickstart 目录 存储库包含此快速入门指南中涵盖的所有版本,以及用于使用注入的 JsonWebToken 令牌及其声明通过 CDI API 演示子资源的其他端点。

我们建议您探索 security-jwt-quickstart 目录,并查看快速入门解决方案,以了解更多有关 SmallRye JWT 扩展的功能。

1.3. 参考指南

1.3.1. 支持的注入范围

org.eclipse.microprofile.jwt.JsonWebToken 被注入时,@ApplicationScoped@Singleton @RequestScoped outer bean 注入范围都是支持。

但是,当将单个令牌声明注入为简单类型(如 String )时,必须使用 @RequestScoped,例如:

package org.acme.security.jwt;

import jakarta.inject.Inject;
import org.eclipse.microprofile.jwt.Claim;
import org.eclipse.microprofile.jwt.Claims;

@Path("/secured")
@RequestScoped
public class TokenSecuredResource {

    @Inject
    @Claim(standard = Claims.birthdate)
    String birthdate;
}
Copy to clipboard

请注意,您也可以使用注入的 JsonWebToken 来访问单个声明,但本例中不需要设置 @RequestScoped

如需了解更多详细信息,请参阅 MP JWT CDI Injection 要求

1.3.2. 支持的公钥格式

可以使用以下格式格式化公钥,按优先级顺序指定:

  • 公钥加密标准 #8 (PKCS""8) PEM
  • JSON Web 密钥(JWK)
  • JSON Web 密钥集(JWKS)
  • JSON Web 密钥(JWK) Base64 URL 编码
  • JSON Web 密钥集(JWKS) Base64 URL 编码

1.3.3. 处理验证密钥

如果您需要使用非对称 RSA 或 Elliptic Curve (EC)密钥验证令牌签名,请使用 mp.jwt.verify.publickey.location 属性来引用本地或远程验证密钥。

使用 mp.jwt.verify.publickey.algorithm 自定义验证算法(默认为 RS256),例如,在使用 EC 密钥时将其设置为 ES256

如果您需要使用对称 secret 密钥验证令牌签名,则必须使用 JSON Web 密钥集(JWK)或 JSON Web 密钥集 (JWK Set)格式来代表此 secret 密钥,例如:

{
 "keys": [
   {
     "kty":"oct",
     "kid":"secretKey",
     "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
   }
 ]
}
Copy to clipboard

此机密密钥 JWK 还必须通过 smallrye.jwt.verify.key.location 来引用。smallrye.jwt.verify.algorithm 应设置为 HS256/HS384/HS512

1.3.4. 使用 JWTParser解析并验证 JsonWebToken

如果 JWT 令牌不能注入,例如,如果在服务请求有效负载中嵌入它,或者服务端点将其从带外获取,则用户可以使用 JWTParser

import org.eclipse.microprofile.jwt.JsonWebToken;
import io.smallrye.jwt.auth.principal.JWTParser;
...
@Inject JWTParser parser;

String token = getTokenFromOidcServer();

// Parse and verify the token
JsonWebToken jwt = parser.parse(token);
Copy to clipboard

您还可以使用它来自定义令牌被验证或解密的方式。例如,一个可以提供本地 SecretKey

package org.acme.security.jwt;

import io.smallrye.jwt.auth.principal.ParseException;
import jakarta.inject.Inject;
import jakarta.ws.rs.CookieParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.NewCookie;
import jakarta.ws.rs.core.Response;
import org.eclipse.microprofile.jwt.JsonWebToken;
import io.smallrye.jwt.auth.principal.JWTParser;
import io.smallrye.jwt.build.Jwt;

@Path("/secured")
public class SecuredResource {
    private static final String SECRET = "AyM1SysPpbyDfgZld3umj1qzKObwVMko";

    @Inject
    JWTParser parser;

    @GET
    @Produces("text/plain")
    public Response getUserName(@CookieParam("jwt") String jwtCookie) throws ParseException {
        if (jwtCookie == null) {
            // Create a JWT token signed by using the 'HS256' algorithm
            String newJwtCookie = Jwt.upn("Alice").signWithSecret(SECRET);
            // or create a JWT token encrypted by using the 'A256KW' algorithm
            // Jwt.upn("alice").encryptWithSecret(secret);
            return Response.ok("Alice").cookie(new NewCookie("jwt", newJwtCookie)).build();
        } else {
            // All mp.jwt and smallrye.jwt properties are still effective; only the verification key is customized.
            JsonWebToken jwt = parser.verify(jwtCookie, SECRET);
            // or jwt = parser.decrypt(jwtCookie, secret);
            return Response.ok(jwt.getName()).build();
        }
    }
}
Copy to clipboard

另请参阅 How to Add SmallRye JWT 部分有关如何使用 JWTParser 部分,而无需 quarkus-smallrye-jwt 提供的 HTTP 支持。

1.3.5. 令牌解密

如果您的应用需要接受带有加密声明或加密声明的令牌,只需设置 smallrye.jwt.decrypt.key.location 属性以指向解密密钥。

如果这是唯一设定的 key 属性,则传入的令牌应该仅包含加密的声明。如果同时设置了 mp.jwt.verify.publickeymp.jwt.verify.publickey.location 验证属性,则传入的令牌应该包含加密的内部令牌。

请参阅 使用 SmallRye JWT 生成 JWT 令牌,了解如何生成加密或内部签名,然后快速生成加密的令牌。

1.3.6. 自定义工厂

io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipalFactory 是用于解析和验证 JWT 令牌的默认实施,将它们转换为 JsonWebToken 主体。此工厂依赖于 MP JWTsmallrye-jwt 属性,如 Configuration 部分所述,以验证和自定义 JWT 令牌。

如果您需要实现自定义工厂(如跳过已由防火墙验证的令牌),您可以使用以下方法之一完成此操作:

  • 通过创建 META-INF/services/io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory 资源来使用 ServiceLoader 机制。
  • 提供 替代 CDI bean 实现,如下例所示:
import java.nio.charset.StandardCharsets;
import java.util.Base64;
import jakarta.annotation.Priority;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.enterprise.inject.Alternative;
import org.jose4j.jwt.JwtClaims;
import org.jose4j.jwt.consumer.InvalidJwtException;
import io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipal;
import io.smallrye.jwt.auth.principal.JWTAuthContextInfo;
import io.smallrye.jwt.auth.principal.JWTCallerPrincipal;
import io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory;
import io.smallrye.jwt.auth.principal.ParseException;

@ApplicationScoped
@Alternative
@Priority(1)
public class TestJWTCallerPrincipalFactory extends JWTCallerPrincipalFactory {

    @Override
    public JWTCallerPrincipal parse(String token, JWTAuthContextInfo authContextInfo) throws ParseException {
        try {
            // Token has already been verified; parse the token claims only
            String json = new String(Base64.getUrlDecoder().decode(token.split("\\.")[1]), StandardCharsets.UTF_8);
            return new DefaultJWTCallerPrincipal(JwtClaims.parse(json));
        } catch (InvalidJwtException ex) {
            throw new ParseException(ex.getMessage());
        }
    }
}
Copy to clipboard

1.3.7. 阻塞调用

quarkus-smallrye-jwt 扩展使用 SmallRye JWT 库,该库目前不是被动的。

quarkus-smallrye-jwt 的视角中,它作为 reactive Quarkus 安全架构的一部分运行,是输入 SmallRye JWT 验证或解密代码之一的 IO 线程可能会在以下情况之一中阻止:

  • 默认密钥解析器会刷新包含密钥的 JsonWebKey 设置,该密钥涉及对 OIDC 端点的远程调用。
  • 自定义密钥解析器,如 AWS Application Load Balancer (ALB)密钥解析器,使用当前令牌的密钥标识符标头值针对 AWS ALB 密钥端点解析密钥。

在这种情况下,如果连接速度较慢,对键端点需要超过 3 秒的时间响应 - 当前事件循环线程可能会被阻止。

要防止它阻止,请设置 quarkus.smallrye-jwt.blocking-authentication=true

1.3.8. 令牌传播

请参阅有关 Bearer 访问令牌传播到下游服务的 Token Propagation 部分。

1.3.9. 测试

1.3.9.1. Wiremock

如果您将 mp.jwt.verify.publickey.location 配置为指向 HTTPS 或基于 HTTP 的 JsonWebKey (JWK)集,则您可以使用与 OpenID Connect Bearer Token Integration 测试 Wiremock 部分中相同的方法,但只需要更改 application.properties 以使用 MP JWT 配置属性:

# keycloak.url is set by OidcWiremockTestResource
mp.jwt.verify.publickey.location=${keycloak.url}/realms/quarkus/protocol/openid-connect/certs
mp.jwt.verify.issuer=${keycloak.url}/realms/quarkus
Copy to clipboard
1.3.9.2. Keycloak

如果您使用 Keycloak,并将 mp.jwt.verify.publickey.location 指向 HTTPS 或基于 HTTP 的 JsonWebKey (JWK)集,您可以使用与 OpenID Connect Bearer Token Integration 测试 部分中描述的相同方法,但只需要更改 application.properties 以使用 MP JWT 配置属性:

# keycloak.url is set by DevServices for Keycloak
mp.jwt.verify.publickey.location=${keycloak.url}/realms/quarkus/protocol/openid-connect/certs
mp.jwt.verify.issuer=${keycloak.url}/realms/quarkus
Copy to clipboard

请注意,Keycloak 发布的令牌会将 iss (issuer)声明设置为 realm 端点地址。

如果您的 Quarkus 应用程序在 Docker 容器中运行,它可能会与由 DevServices for Keycloak 启动的 Keycloak 容器共享一个网络接口。在这种情况下,Quarkus 应用程序和 Keycloak 通过内部共享 Docker 网络进行通信。

在这种情况下,使用以下配置:

# keycloak.url is set by DevServices for Keycloak,
# Quarkus accesses it through an internal shared docker network interface.
mp.jwt.verify.publickey.location=${keycloak.url}/realms/quarkus/protocol/openid-connect/certs

# Issuer is set to the docker bridge localhost endpoint address represented by the `client.quarkus.oidc.auth-server-url` property
mp.jwt.verify.issuer=${client.quarkus.oidc.auth-server-url}
Copy to clipboard
1.3.9.3. 本地公钥

您可以使用与 OpenID Connect Bearer Token Integration 测试 本地公钥 部分中所述的方法相同,但仅将 application.properties 更改为使用 MP JWT 配置属性:

mp.jwt.verify.publickey=MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEqFyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwRTYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5eUF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYnsIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9xnQIDAQAB
# set it to the issuer value which is used to generate the tokens
mp.jwt.verify.issuer=${keycloak.url}/realms/quarkus

# required to sign the tokens
smallrye.jwt.sign.key.location=privateKey.pem
Copy to clipboard
1.3.9.4. TestSecurity 注解

添加以下依赖项:

  • 使用 Maven:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-test-security-jwt</artifactId>
        <scope>test</scope>
    </dependency>
    Copy to clipboard
  • 使用 Gradle:

    testImplementation("io.quarkus:quarkus-test-security-jwt")
    Copy to clipboard

然后,编写测试代码,如下所示:

import static org.hamcrest.Matchers.is;
import org.junit.jupiter.api.Test;
import io.quarkus.test.common.http.TestHTTPEndpoint;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.security.TestSecurity;
import io.quarkus.test.security.jwt.Claim;
import io.quarkus.test.security.jwt.JwtSecurity;
import io.restassured.RestAssured;

@QuarkusTest
@TestHTTPEndpoint(ProtectedResource.class)
public class TestSecurityAuthTest {

    @Test
    @TestSecurity(user = "userJwt", roles = "viewer")
    public void testJwt() {
        RestAssured.when().get("test-security-jwt").then()
                .body(is("userJwt:viewer"));
    }

    @Test
    @TestSecurity(user = "userJwt", roles = "viewer")
    @JwtSecurity(claims = {
            @Claim(key = "email", value = "user@gmail.com")
    })
    public void testJwtWithClaims() {
        RestAssured.when().get("test-security-jwt-claims").then()
                .body(is("userJwt:viewer:user@gmail.com"));
    }

}
Copy to clipboard

其中 ProtectedResource 类可能类似如下:

@Path("/web-app")
@Authenticated
public class ProtectedResource {

    @Inject
    JsonWebToken accessToken;

    @GET
    @Path("test-security-jwt")
    public String testSecurityOidc() {
        return accessToken.getName() + ":" + accessToken.getGroups().iterator().next();
    }

    @GET
    @Path("test-security-jwt-claims")
    public String testSecurityOidcUserInfoMetadata() {
        return accessToken.getName() + ":" + accessToken.getGroups().iterator().next()
                + ":" + accessToken.getClaim("email");
    }
}
Copy to clipboard

请注意,必须始终使用 @TestSecurity 注释,并且其 user 属性返回为 JsonWebToken.getName ()roles 属性 - 作为 JsonWebToken.getGroups ()@JwtSecurity 注释是可选的,可用于设置额外的令牌声明。

提示

@TestSecurity@JwtSecurity 可以合并到 meta-annotation 中,如下所示:

    @Retention(RetentionPolicy.RUNTIME)
    @Target({ ElementType.METHOD })
    @TestSecurity(user = "userOidc", roles = "viewer")
    @OidcSecurity(introspectionRequired = true,
        introspection = {
            @TokenIntrospection(key = "email", value = "user@gmail.com")
        }
    )
    public @interface TestSecurityMetaAnnotation {

    }
Copy to clipboard

如果在多个测试方法中使用同一组安全设置,这特别有用。

1.3.10. 如何检查日志中的错误

请启用 io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator 级别日志记录,以查看令牌验证或解密错误的更多详情:

quarkus.log.category."io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator".level=TRACE
quarkus.log.category."io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator".min-level=TRACE
Copy to clipboard

1.3.11. 主动验证

如果您想在调用公共端点方法时跳过令牌验证,请禁用 主动身份验证

请注意,如果没有令牌验证,则无法通过公共方法访问注入的 JsonWebToken

1.3.12. 如何直接添加 SmallRye JWT

要使用 JWTParser 解析并验证 JsonWebToken,请在以下情况中使用 smallrye-jwt 而不是 quarkus-smallrye-jwt

  • 您可以使用不支持 HTTP 的 Quarkus 扩展,如 Quarkus GRPC
  • 您可以提供一个特定于扩展的 HTTP,它的支持与 quarkus-smallrye-jwtVert.x HTTP 提供的支持冲突,如 Quarkus AWS Lambda

从添加 smallrye-jwt 依赖项开始:

  • 使用 Maven:

    <dependency>
        <groupId>io.smallrye</groupId>
        <artifactId>smallrye-jwt</artifactId>
    </dependency>
    Copy to clipboard
  • 使用 Gradle:

    implementation("io.smallrye:smallrye-jwt")
    Copy to clipboard

然后,更新 application.properties 以获取 smallrye-jwt 提供的所有 CDI 生成者,如下所示:

quarkus.index-dependency.smallrye-jwt.group-id=io.smallrye
quarkus.index-dependency.smallrye-jwt.artifact-id=smallrye-jwt
Copy to clipboard

1.4. 配置参考

1.4.1. Quarkus 配置

lock 在构建时修复的配置属性 - 所有其他配置属性在运行时可覆盖

配置属性

类型

default

lock quarkus.smallrye-jwt.enabled

MP-JWT 配置对象

环境变量: QUARKUS_SMALLRYE_JWT_ENABLED

布尔值

true

lock quarkus.smallrye-jwt.rsa-sig-provider

支持 SHA256withRSA 签名的 java.security.Provider 的名称

环境变量: QUARKUS_SMALLRYE_JWT_RSA_SIG_PROVIDER

string

SunRSASign

quarkus.smallrye-jwt.blocking-authentication

如果获取远程密钥是一个耗时的操作,则启用此属性。如果您使用本地密钥,请不要启用它。

环境变量: QUARKUS_SMALLRYE_JWT_BLOCKING_AUTHENTICATION

布尔值

false

quarkus.smallrye-jwt.silent

始终创建 HTTP 401 质询,即使对于不包含身份验证凭据的请求。当需要身份验证时,JWT 身份验证机制将返回 HTTP 401。但是,如果它与其中一个交互式身份验证机制一起使用,那么可能不希望将 HTTP 401 返回到从浏览器访问应用的用户。如果您希望请求 JWT 身份验证机制在这样的情形中不会产生挑战,方法是将此属性设置为"true"。

环境变量: QUARKUS_SMALLRYE_JWT_SILENT

布尔值

false

1.4.2. MicroProfile JWT 配置

属性名称default描述

mp.jwt.verify.publickey

none

mp.jwt.verify.publickey 配置属性允许以字符串形式提供公钥文本。公钥从提供的字符串解析,按 支持的公钥格式部分定义的顺序

mp.jwt.verify.publickey.location

none

config 属性允许公钥的指定外部或内部位置。该值可以是相对路径或 URL。如果值指向基于 HTTPS 的 JWK 集,那么对于它以原生模式工作,则 quarkus.ssl.native 属性也必须设置为 true。如需了解更多详细信息,请参阅使用带有原生 Executables 的 SSL

mp.jwt.verify.publickey.algorithm

RS256

签名算法列表。将它设置为 ES256 以支持 Elliptic Curve 签名算法。

mp.jwt.decrypt.key.location

none

config 属性允许 Private Decryption Key 的指定外部或内部位置。

mp.jwt.decrypt.key.algorithm

RSA-OAEP,RSA-OAEP-256

解密算法列表。把它设置为 RSA-OAEP-256 以支持带有 SHA-256 的 RSA-OAEP。

mp.jwt.verify.issuer

none

config 属性指定服务器接受有效的 JWT 的 iss (issuer)声明的值。

mp.jwt.verify.audiences

none

以逗号分隔的令牌 声明 列表可能包含:

mp.jwt.verify.clock.skew

60

在令牌过期和年龄验证过程中使用的时钟偏移(以秒为单位)。如果当前时间在令牌到期时间后此属性指定的秒数内,则接受已过期令牌。默认值为 60 秒。

mp.jwt.verify.token.age

none

因为令牌 iat (在)时间后,必须未经过的秒数。

mp.jwt.token.header

授权

如果使用另一个标头(如 Cookie )传递令牌,则设置此属性。

mp.jwt.token.cookie

none

包含令牌的 Cookie 名称。只有 mp.jwt.token.header 设置为 Cookie 时,此属性才有效。

1.4.3. 其他 SmallRye JWT 配置

smallrye JWT 提供了更多属性,可用于自定义令牌处理:

属性名称default描述

smallrye.jwt.verify.secretkey

none

作为字符串提供的 secret 密钥。

smallrye.jwt.verify.key.location

NONE

验证密钥的位置,它可以指向公钥和机密密钥。机密密钥只能采用 JWK 格式。请注意,如果设置了此属性,则 'mp.jwt.verify.publickey.location' 会被忽略。

smallrye.jwt.verify.algorithm

 

签名算法.此属性应仅用于设置对称算法,如 HS256。它已被弃用,用于设置非对称算法,如 ES256- 使用 'mp.jwt.verify.publickey.algorithm'。

smallrye.jwt.verify.key-format

ANY

将此属性设置为特定的密钥格式,如 PEM_KEYPEM_CERTIFICATEJWKJWK_BASE64URL,以优化加载验证密钥的方式。

smallrye.jwt.verify.key-provider

DEFAULT

默认情况下,可以使用 PEM、JWK 或 JWK 密钥集从本地文件系统读取或根据 MicroProfile JWT 规范的要求从 URI 获取。将此属性设置为 AWS_ALB 以支持 AWS Application Load Balancer 验证密钥解析。

smallrye.jwt.verify.relax-key-validation

false

对验证密钥的验证 ; 将此属性设置为 true 允许公共 RSA 密钥长度小于 2048 位。

smallrye.jwt.verify.certificate-thumbprint

false

如果启用了此属性,签名的令牌必须包含 'x5t' 或 'x5t SerialS256' X509Certificate thumbprint 标头。验证密钥只能采用 JWK 或 PEM 证书密钥格式。JWK 密钥必须设置 'x5c'(Base64 编码的 X509Certificate)属性。

smallrye.jwt.token.header

授权

如果使用另一个标头(如 Cookie )传递令牌,则设置此属性。此属性已弃用 - 使用 'mp.jwt.token.header'。

smallrye.jwt.key-cache-size

100

密钥缓存大小。当密钥提供程序(如 AWS_ALB )配置了 smallrye.jwt.verify.key-provider=AWS_ALB 时,使用此属性和 smallrye.jwt.key-cache-time-to-live 控制密钥缓存。

smallrye.jwt.key-cache-time-to-live

10

密钥缓存条目时间(以分钟为单位)当密钥提供程序(如 AWS_ALB )配置了 smallrye.jwt.key- provider=AWS_ALB 时,使用此属性和 smallrye.jwt.key-cache- size 来控制密钥缓存,以动态解析密钥。

smallrye.jwt.token.cookie

none

包含令牌的 Cookie 名称。只有在 smallrye.jwt.token.header 设为 Cookie 时,此属性才有效。此属性已弃用 - 使用 mp.jwt.token.cookie

smallrye.jwt.always-check-authorization

false

即使将 smallrye.jwt.token.header 设置为 Cookie,但没有具有 smallrye.jwt.token.cookie 名称的 Cookie,也可以将此属性设置为 true

smallrye.jwt.token.schemes

bearer

包含替代单一或多个方案(如 DPoP )的以逗号分隔的列表。

smallrye.jwt.token.kid

none

键标识符。如果已设置,验证 JWK 密钥和每个 JWT 令牌必须具有匹配的 kid 标头。

smallrye.jwt.time-to-live

none

可以签发 JWT 以供使用的最大秒数。实际上,JWT 和当前发布的过期日期之间的差别不得超过这个值。将此属性设置为非正数值,调整令牌的要求,使其具有有效的"iat" (签发)声明。

smallrye.jwt.require.named-principal

true

如果应用程序依赖于 java.security.Principal 返回名称,则令牌必须设置 upnpreferred_usernamesub 声明。设置此属性会导致 SmallRye JWT 会在没有这些声明可用于可靠地处理非null Principal 名称时抛出异常。

smallrye.jwt.path.sub

none

包含主题名称的声明的路径。它从顶级 JSON 对象开始,并且可以包含多个片段,每个片段仅代表 JSON 对象名称,如 realms/subject。如果令牌没有 'sub' 声明,但在不同声明中设置主题,则可以使用此属性。对命名空间限定声明使用双引号。

smallrye.jwt.claims.sub

none

当当前令牌没有标准或自定义子声明可用时,此属性可以设置默认 声明值。如果未设置 upnpreferred_usernamesub 声明,则此属性可用于自定义 java.security.Principal 名称。

smallrye.jwt.path.groups

none

包含组的声明的路径。它从顶级 JSON 对象开始,可以包含多个片段,每个片段仅代表 JSON 对象名称,例如: realm/groups。如果令牌没有 'groups' 声明,但在不同声明中设置了组,则可以使用此属性。对命名空间限定声明使用双引号。

smallrye.jwt.groups-separator

space

分割字符串的分隔符可能包含多个组值。只有在 smallrye.jwt.path.groups 属性指向带有字符串值的自定义声明时,才会使用它。默认值为单个空格,因为标准 OAuth2 范围 声明可能包含空格分隔的序列。

smallrye.jwt.claims.groups

none

当当前令牌没有可用的标准或自定义组声明时,此属性可以设置默认 groups 声明值。

smallrye.jwt.jwks.refresh-interval

60

JWK 缓存刷新间隔(以分钟为单位)。除非 mp.jwt.verify.publickey.location 指向基于 HTTP 或 HTTPS URL 的 JWK 设置,且没有 HTTP Cache-Control 响应标头,且不会从 JWK HTTPS 端点返回带有正 max-age 参数值的 HTTP Cache-Control 响应标头。

smallrye.jwt.jwks.forced-refresh-interval

30

强制 JWK 缓存刷新间隔(以分钟为单位),用于限制强制刷新尝试的频率,因为缓存没有 JWK 密钥与当前令牌的 kid 属性匹配。除非 mp.jwt.verify.publickey.location 指向 HTTP 或基于 HTTPS URL 的 JWK 设置,否则它会被忽略。

smallrye.jwt.expiration.grace

0

过期宽限期(以秒为单位)。默认情况下,如果在令牌到期时间后当前时间不超过 1 分钟,则过期的令牌仍然被接受。此属性已弃用。使用 mp.jwt.verify.clock.skew 替代。

smallrye.jwt.verify.aud

none

以逗号分隔的令牌 声明 列表可能包含:此属性已弃用 - 使用 mp.jwt.verify.audiences

smallrye.jwt.required.claims

none

以逗号分隔的声明列表必须包含。

smallrye.jwt.decrypt.key.location

none

config 属性来指定 Private Decryption Key 的外部或内部位置。此属性已弃用 - 使用 mp.jwt.decrypt.key.location

smallrye.jwt.decrypt.algorithm

RSA_OAEP

解密算法.

smallrye.jwt.decrypt.key

none

作为字符串提供的解密密钥。

smallrye.jwt.token.decryption.kid

none

解密密钥标识符.如果设置了,则解密 JWK 密钥以及每个 JWT 令牌必须具有匹配的 kid 标头。

smallrye.jwt.client.tls.certificate.path

none

如果需要通过 HTTPS 获取密钥,可能需要配置 TLS 可信证书的路径。

smallrye.jwt.client.tls.trust-all

false

信任所有主机名。如果需要通过 HTTPS 获取密钥,并且此属性设置为 true,则所有主机名都默认是可信的。

smallrye.jwt.client.tls.hosts

none

组可信主机名。如果密钥必须通过 HTTPS 获取,并且 smallrye.jwt.client.tls.trust-all 被设置为 false,则此属性可用于配置可信主机名。

smallrye.jwt.http.proxy.host

none

HTTP 代理主机.

smallrye.jwt.http.proxy.port

80

HTTP 代理端口。

smallrye.jwt.keystore.type

JKS

如果 mp.jwt.verify.publickey.locationmp.jwt.decrypt.key.location 指向 KeyStore 文件,则此属性可用于自定义密钥存储类型。如果没有设置,则会检查文件名,以确定密钥类型,然后再默认为 JKS

smallrye.jwt.keystore.provider

 

如果 mp.jwt.verify.publickey.locationmp.jwt.decrypt.key.location 指向 KeyStore 文件,则此属性可用于自定义 KeyStore 供应商。

smallrye.jwt.keystore.password

 

密钥存储密码。如果 mp.jwt.verify.publickey.locationmp.jwt.decrypt.key.location,则必须设置此属性。

smallrye.jwt.keystore.verify.key.alias

 

如果 mp.jwt.verify.publickey.location 指向 KeyStore 文件,则必须设置此属性来识别从 KeyStore 中提取的公共验证密钥。

smallrye.jwt.keystore.decrypt.key.alias

 

如果 mp.jwt.decrypt.key.location 指向 KeyStore 文件,则必须设置此属性来识别私有解密密钥。

smallrye.jwt.keystore.decrypt.key.password

 

如果 KeyStore 中的私钥密码与 smallrye.jwt.keystore.passwordmp.jwt.decrypt.key.location 指向 KeyStore 文件时,可以设置此属性。

smallrye.jwt.resolve-remote-keys-at-startup

false

将此属性设置为 true,以在应用启动时解析远程密钥。

1.5. 参考

第 2 章 构建、签名和加密 JSON Web 令牌

JSON Web 令牌(JWT)由 RFC 7519 规范定义为代表声明的紧凑 URL 安全方法。这些声明被编码为 JSON 对象,可用作 JSON Web 签名(JWS)结构的有效负载或 JSON Web 加密(JWE)结构的纯文本。这种机制使声明可以进行数字签名或保护,以获得消息身份验证代码(MAC)并加密的完整性。

签名声明是保护声明的最常见方法。通常,通过签名声明以 JSON 格式生成 JWT 令牌,遵循 JSON Web 签名(JWS) 规范中所述的步骤。

当声明包含敏感信息时,可以使用 JSON Web 加密(JWE) 规范来确保其机密。此方法生成带有加密声明的 JWT。

为提高安全性,您可以组合这两种方法:首先对声明进行签名,然后加密生成的嵌套 JWT。此过程可确保声明的机密性和完整性。

SmallRye JWT Build API 通过支持所有这些选项来简化 JWT 声明的安全。它在内部使用 Jose4J 库来提供此功能。

2.1. 依赖项

要使用 SmallRye JWT Build API,请将以下依赖项添加到项目中:

  • 使用 Maven:

    <dependency>
        <groupId>io.quarkus</groupId>
        <artifactId>quarkus-smallrye-jwt-build</artifactId>
    </dependency>
    Copy to clipboard
  • 使用 Gradle:

    implementation("io.quarkus:quarkus-smallrye-jwt-build")
    Copy to clipboard

您可以独立使用 SmallRye JWT Build API,而不创建 quarkus-smallrye-jwt 扩展支持的 MicroProfile JWT 端点。

2.2. 创建 JwtClaimsBuilder 并设置声明

第一步是使用以下选项之一初始化 JwtClaimsBuilder,并将一些声明添加到其中:

import java.util.Collections;
import jakarta.json.Json;
import jakarta.json.JsonObject;
import io.smallrye.jwt.build.Jwt;
import io.smallrye.jwt.build.JwtClaimsBuilder;
import org.eclipse.microprofile.jwt.JsonWebToken;
...
// Create an empty builder and add some claims
JwtClaimsBuilder builder1 = Jwt.claims();
builder1.claim("customClaim", "custom-value").issuer("https://issuer.org");
// Alternatively, start with claims directly:
// JwtClaimsBuilder builder1 = Jwt.upn("Alice");

// Create a builder from an existing claims file
JwtClaimsBuilder builder2 = Jwt.claims("/tokenClaims.json");

// Create a builder from a map of claims
JwtClaimsBuilder builder3 = Jwt.claims(Collections.singletonMap("customClaim", "custom-value"));

// Create a builder from a JsonObject
JsonObject userName = Json.createObjectBuilder().add("username", "Alice").build();
JsonObject userAddress = Json.createObjectBuilder().add("city", "someCity").add("street", "someStreet").build();
JsonObject json = Json.createObjectBuilder(userName).add("address", userAddress).build();
JwtClaimsBuilder builder4 = Jwt.claims(json);

// Create a builder from a JsonWebToken
@Inject JsonWebToken token;
JwtClaimsBuilder builder5 = Jwt.claims(token);
Copy to clipboard

API 非常流畅,以便您可以将构建器初始化为流畅序列的一部分。

如果没有明确配置,构建程序会自动设置以下声明:

  • iat (在以下位置发出):当前时间
  • exp (expires at):自当前时间起的五分钟(可定制为 smallrye.jwt.new-token.lifespan 属性)
  • jti (唯一令牌标识符)

您可以在全局范围内配置以下属性,以避免直接在构建器中设置它们:

  • smallrye.jwt.new-token.issuer: 指定默认签发者。
  • smallrye.jwt.new-token.audience: 指定默认受众。

初始化和设置声明后,下一步是决定如何保护声明。

2.3. 为声明签名

您可以立即或在配置 JSON Web 签名(JWS)标头后为声明签名

import io.smallrye.jwt.build.Jwt;
...

// Sign the claims using an RSA private key loaded from the location specified by the 'smallrye.jwt.sign.key.location' property.
// No 'jws()' transition is required. The default algorithm is RS256.
String jwt1 = Jwt.claims("/tokenClaims.json").sign();

// Set the headers and sign the claims by using an RSA private key loaded in the code (the implementation of this method is omitted).
// Includes a 'jws()' transition to a 'JwtSignatureBuilder'. The default algorithm is RS256.

String jwt2 = Jwt.claims("/tokenClaims.json")
                 .jws()
                 .keyId("kid1")
                 .header("custom-header", "custom-value")
                 .sign(getPrivateKey());
Copy to clipboard

默认行为:

  • 默认情况下 alg (算法)标头设置为 RS256
  • 如果使用包含kid 属性的单个 JSON Web Key (JWK),则不必设置签名密钥标识符( kid 标头)。

支持的密钥和算法:

  • 要签署声明,您可以使用 RSA 私钥、Eliptic Curve (EC)私钥和对称 secret 密钥。
  • RS256 是默认的 RSA 私钥签名算法。
  • ES256 是默认的 EC 私钥签名算法。
  • HS256 是默认的对称密钥签名算法。

若要自定义签名算法,可使用 JwtSignatureBuilder API。例如:

import io.smallrye.jwt.SignatureAlgorithm;
import io.smallrye.jwt.build.Jwt;

// Sign the claims using an RSA private key loaded from the location set with a 'smallrye.jwt.sign.key.location' property. The algorithm is PS256.
String jwt = Jwt.upn("Alice").jws().algorithm(SignatureAlgorithm.PS256).sign();
Copy to clipboard

另外,您可以使用以下属性全局配置签名算法:

smallrye.jwt.new-token.signature-algorithm=PS256
Copy to clipboard

这个方法为您提供了一个简单的 API 序列:

import io.smallrye.jwt.build.Jwt;

// Sign the claims using an RSA private key loaded from the location set with a 'smallrye.jwt.sign.key.location' property. The algorithm is PS256.
String jwt = Jwt.upn("Alice").sign();
Copy to clipboard

您可以将 签名步骤与 加密 步骤相结合,以创建 内部签名和加密 的令牌。如需更多信息,请参阅 签名声明并加密嵌套的 JWT 令牌 部分。

2.4. 加密声明

您可以立即加密声明,或者在设置 JSON Web 加密(JWE) 标头后加密声明,类似于如何签署声明。但是,加密声明始终需要一个 jwe () 转换为 JwtEncryptionBuilder,因为 API 被优化以支持签名和内部签名操作。

import io.smallrye.jwt.build.Jwt;
...

// Encrypt the claims using an RSA public key loaded from the location specified by the 'smallrye.jwt.encrypt.key.location' property.
// The default key encryption algorithm is RSA-OAEP.

String jwt1 = Jwt.claims("/tokenClaims.json").jwe().encrypt();

// Set the headers and encrypt the claims by using an RSA public key loaded in the code (the implementation of this method is omitted).
// The default key encryption algorithm is A256KW.
String jwt2 = Jwt.claims("/tokenClaims.json").jwe().header("custom-header", "custom-value").encrypt(getSecretKey());
Copy to clipboard

默认行为:

  • alg (密钥管理算法)标头默认为 RSA-OAEP
  • enc (内容加密)标头默认为 A256GCM

支持的密钥和算法:

  • 您可以使用 RSA 公钥、Elliptic Curve (EC)公钥和对称 secret 密钥来加密声明。
  • RSA-OAEP 是默认的 RSA 公钥加密算法。
  • ECDH-ES 是默认的 EC 公钥加密算法。
  • A256KW 是默认的对称密钥加密算法。

请注意,在创建加密令牌时执行两个加密操作:

  1. 生成的内容加密密钥是使用提供的密钥和密钥加密算法(如 RSA-OAEP )进行加密。
  2. 该声明使用内容加密密钥和内容加密算法(如 A256GCM )进行加密。

您可以使用 JwtEncryptionBuilder API 自定义密钥和证书算法。例如:

import io.smallrye.jwt.KeyEncryptionAlgorithm;
import io.smallrye.jwt.ContentEncryptionAlgorithm;
import io.smallrye.jwt.build.Jwt;

// Encrypt the claims using an RSA public key loaded from the location set with a 'smallrye.jwt.encrypt.key.location' property.
// Key encryption algorithm is RSA-OAEP-256. The content encryption algorithm is A256CBC-HS512.

String jwt = Jwt.subject("Bob").jwe()
    .keyAlgorithm(KeyEncryptionAlgorithm.RSA_OAEP_256)
    .contentAlgorithm(ContentEncryptionAlgorithm.A256CBC_HS512)
    .encrypt();
Copy to clipboard

另外,您可以使用以下属性全局配置算法:

smallrye.jwt.new-token.key-encryption-algorithm=RSA-OAEP-256
smallrye.jwt.new-token.content-encryption-algorithm=A256CBC-HS512
Copy to clipboard

此配置允许更简单的 API 序列:

import io.smallrye.jwt.build.Jwt;

// Encrypt the claims by using an RSA public key loaded from the location set with a 'smallrye.jwt.encrypt.key.location' property.
// Key encryption algorithm is RSA-OAEP-256. The content encryption algorithm is A256CBC-HS512.
String jwt = Jwt.subject("Bob").encrypt();
Copy to clipboard

安全令牌加密建议:

  • 当令牌直接使用公共 RSA 或 EC 密钥加密时,无法验证哪个方发送令牌。为解决此问题,最好使用对称 secret 密钥进行直接加密,特别是在将 JWT 用作 Cookie 仅由 Quarkus 端点管理时。
  • 要使用 RSA 或 EC 公钥加密令牌,如果有签名密钥,则建议首先为令牌签名。如需更多信息,请参阅 签名声明并加密嵌套的 JWT 令牌 部分。

2.5. 为声明签名并加密嵌套的 JWT 令牌

您可以签署声明,然后通过组合签名和加密步骤来加密嵌套的 JWT 令牌。

import io.smallrye.jwt.build.Jwt;
...

// Sign the claims and encrypt the nested token using the private and public keys loaded from the locations
// specified by the 'smallrye.jwt.sign.key.location' and 'smallrye.jwt.encrypt.key.location' properties, respectively.
// The signature algorithm is RS256, and the key encryption algorithm is RSA-OAEP-256.
String jwt = Jwt.claims("/tokenClaims.json").innerSign().encrypt();
Copy to clipboard

2.6. 快速 JWT 生成

如果设置了 smallrye.jwt.sign.key.locationsmallrye.jwt.encrypt.key.location 属性,您可以使用单个调用来保护现有的声明,如 resources, maps, JsonObjects :

// More compact than Jwt.claims("/claims.json").sign();
Jwt.sign("/claims.json");

// More compact than Jwt.claims("/claims.json").jwe().encrypt();
Jwt.encrypt("/claims.json");

// More compact than Jwt.claims("/claims.json").innerSign().encrypt();
Jwt.signAndEncrypt("/claims.json");
Copy to clipboard

如前文所述,如果尚未设置,则会自动添加以下声明: iat (issued at), exp (expires at), jti (token identifier), iss (issuer)和 aud (audience)。

2.7. 处理密钥

您可以使用 smallrye.jwt.sign.key.locationsmallrye.jwt.encrypt.key.location 属性来指定签名和加密密钥的位置。这些密钥可以位于本地文件系统上,位于 classpath 上,或者从远程端点获取。密钥可以是 PEMJSON Web 密钥(JWK) 格式。例如:

smallrye.jwt.sign.key.location=privateKey.pem
smallrye.jwt.encrypt.key.location=publicKey.pem
Copy to clipboard

或者,您可以使用 MicroProfile ConfigSourcesmallrye.jwt.sign.keysmallrye.jwt.encrypt.key 属性从外部服务获取密钥,如 HashiCorp Vault 或其他 secret 管理器:

smallrye.jwt.sign.key=${private.key.from.vault}
smallrye.jwt.encrypt.key=${public.key.from.vault}
Copy to clipboard

在本例中,private.key.from.vaultpublic.key.from.vaultPEMJWK 格式的密钥值,由自定义 ConfigSource 提供。

smallrye.jwt.sign.keysmallrye.jwt.encrypt.key 属性也可以直接包含 base64 编码的私钥或公钥值。

但请注意,不建议在配置中直接显示私钥。仅在需要从远程 secret manager 获取签名密钥值时,才使用 smallrye.jwt.sign.key 属性。

密钥也可以由构建令牌的代码加载,然后提供给 JWT Build API 以进行令牌创建。

如果您需要使用对称 secret 密钥签名或加密令牌,请考虑使用 io.smallrye.jwt.util.KeyUtils 生成所需长度的 SecretKey

例如,需要使用 HS512 算法(512/8)为令牌签名 64 字节密钥,需要使用 A256KW 算法加密内容加密密钥(256/8):

import javax.crypto.SecretKey;
import io.smallrye.jwt.KeyEncryptionAlgorithm;
import io.smallrye.jwt.SignatureAlgorithm;
import io.smallrye.jwt.build.Jwt;
import io.smallrye.jwt.util.KeyUtils;

SecretKey signingKey = KeyUtils.generateSecretKey(SignatureAlgorithm.HS512);
SecretKey encryptionKey = KeyUtils.generateSecretKey(KeyEncryptionAlgorithm.A256KW);
String jwt = Jwt.claim("sensitiveClaim", getSensitiveClaim()).innerSign(signingKey).encrypt(encryptionKey);
Copy to clipboard

您还可以考虑使用 JSON Web 密钥(JWK)或 JSON Web 密钥集(JWK Set)格式将 secret 密钥存储在安全文件系统中。您可以使用 smallrye.jwt.sign.key.locationsmallrye.jwt.encrypt.key.location 属性来引用密钥。

JWK 示例

{
 "kty":"oct",
 "kid":"secretKey",
 "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I"
}
Copy to clipboard

JWK 设置示例

{
 "keys": [
   {
     "kty":"oct",
     "kid":"secretKey1",
     "k":"Fdh9u8rINxfivbrianbbVT1u232VQBZYKx1HGAGPt2I"
   },
   {
     "kty":"oct",
     "kid":"secretKey2",
     "k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
   }
 ]
}
Copy to clipboard

您还可以使用 io.smallrye.jwt.util.KeyUtils 生成一对非对称 RSA 或 EC 密钥。这些密钥可以存储 JWKJWK SetPEM 格式。

2.8. smallrye JWT Builder 配置

smallrye JWT 支持以下属性,可用于自定义声明如何签名或加密:

属性名称default描述

smallrye.jwt.sign.key.location

none

当调用 no-argument 符号 ()或 innerSign () 方法时,用于签署 声明的私钥的位置。

smallrye.jwt.sign.key

none

当调用 no-argument sign ()innerSign () 方法时,用于签署声明的键值。

smallrye.jwt.sign.key.id

none

签名密钥标识符,仅在使用 JWK 密钥时检查。

smallrye.jwt.encrypt.key.location

none

调用 no-argument encrypt () 方法时,用于加密声明或内部 JWT 的公钥的位置。

smallrye.jwt.sign.relax-key-validation

false

对签名密钥的验证进行 Relax 操作。

smallrye.jwt.encrypt.key

none

调用 no-argument encrypt () 方法时,用于加密声明或内部 JWT 的键值。

smallrye.jwt.encrypt.key.id

none

加密密钥标识符,仅在使用 JWK 密钥时检查。

smallrye.jwt.encrypt.relax-key-validation

false

对加密密钥的验证进行 Relax 操作。

smallrye.jwt.new-token.signature-algorithm

RS256

签名算法.检查 JWT 签名构建器尚未设置签名算法。

smallrye.jwt.new-token.key-encryption-algorithm

RSA-OAEP

密钥加密算法。检查 JWT 加密构建器尚未设置密钥加密算法。

smallrye.jwt.new-token.content-encryption-algorithm

A256GCM

内容加密算法。检查 JWT 加密构建器尚未设置内容加密算法。

smallrye.jwt.new-token.lifespan

300

如果尚未设置此声明,令牌生命周期(以秒为单位)用于计算 exp (expiry)声明值。

smallrye.jwt.new-token.issuer

none

如果尚未设置此声明,用于设置 iss (issuer)声明值的令牌签发者。

smallrye.jwt.new-token.audience

none

如果尚未设置此声明,用于设置 aud (audience)声明值的令牌使用者。

smallrye.jwt.new-token.override-matching-claims

false

对于 smallrye.jwt.new-token.issuersmallrye.jwt.new-token.audience 值,将此属性设为 true,以覆盖已初始化的 iss (issuer)和 aud (audience)声明。

smallrye.jwt.keystore.type

JKS

如果 smallrye.jwt.sign.key.locationsmallrye.jwt.encrypt.key.location 或这两个属性都指向 KeyStore 文件,则此属性可用于自定义密钥存储类型。如果没有设置,则将检查文件名,以确定密钥存储类型,然后再默认为 JKS

smallrye.jwt.keystore.provider

 

如果 smallrye.jwt.sign.key.locationsmallrye.jwt.encrypt.key.location 指向 KeyStore 文件,则此属性可用于自定义 KeyStore 提供程序。

smallrye.jwt.keystore.password

 

密钥存储密码。如果 smallrye.jwt.sign.key.locationsmallrye.jwt.encrypt.key.location 指向 KeyStore 文件,则必须设置此属性。

smallrye.jwt.keystore.encrypt.key.alias

 

如果 smallrye.encrypt.key.location 指向 KeyStore 文件,则必须设置此属性来识别从 KeyStore 从 KeyStore 中提取的公共加密密钥。

smallrye.jwt.keystore.sign.key.alias

 

如果 smallrye.jwt.sign.key.location 指向 KeyStore 文件,则必须设置此属性来识别私有签名密钥。

smallrye.jwt.keystore.sign.key.password

 

如果 KeyStore 中的私钥密码与 smallrye.jwt.keystore.passwordsmallrye.jwt.sign.key.location 指向 KeyStore 文件时,可以设置此属性。

2.9. 参考

法律通告

Copyright © 2025 Red Hat, Inc.
The text of and illustrations in this document are licensed by Red Hat under a Creative Commons Attribution–Share Alike 3.0 Unported license ("CC-BY-SA"). An explanation of CC-BY-SA is available at http://creativecommons.org/licenses/by-sa/3.0/. In accordance with CC-BY-SA, if you distribute this document or an adaptation of it, you must provide the URL for the original version.
Red Hat, as the licensor of this document, waives the right to enforce, and agrees not to assert, Section 4d of CC-BY-SA to the fullest extent permitted by applicable law.
Red Hat, Red Hat Enterprise Linux, the Shadowman logo, the Red Hat logo, JBoss, OpenShift, Fedora, the Infinity logo, and RHCE are trademarks of Red Hat, Inc., registered in the United States and other countries.
Linux® is the registered trademark of Linus Torvalds in the United States and other countries.
Java® is a registered trademark of Oracle and/or its affiliates.
XFS® is a trademark of Silicon Graphics International Corp. or its subsidiaries in the United States and/or other countries.
MySQL® is a registered trademark of MySQL AB in the United States, the European Union and other countries.
Node.js® is an official trademark of Joyent. Red Hat is not formally related to or endorsed by the official Joyent Node.js open source or commercial project.
The OpenStack® Word Mark and OpenStack logo are either registered trademarks/service marks or trademarks/service marks of the OpenStack Foundation, in the United States and other countries and are used with the OpenStack Foundation's permission. We are not affiliated with, endorsed or sponsored by the OpenStack Foundation, or the OpenStack community.
All other trademarks are the property of their respective owners.
返回顶部
Red Hat logoGithubredditYoutubeTwitter

学习

尝试、购买和销售

社区

关于红帽文档

通过我们的产品和服务,以及可以信赖的内容,帮助红帽用户创新并实现他们的目标。 了解我们当前的更新.

让开源更具包容性

红帽致力于替换我们的代码、文档和 Web 属性中存在问题的语言。欲了解更多详情,请参阅红帽博客.

關於紅帽

我们提供强化的解决方案,使企业能够更轻松地跨平台和环境(从核心数据中心到网络边缘)工作。

Theme

© 2025 Red Hat, Inc.