JWT RBAC の使用
このガイドでは、Quarkusアプリケーションが SmallRye JWT を利用して、 JSON Web Token を検証し、MicroProfile JWT org.eclipse.microprofile.jwt.JsonWebToken
として表現し、Bearer Token Authorizationと Role-Based Access Control を使用してQuarkus HTTPエンドポイントへのセキュアなアクセスを提供する方法について説明します。
Quarkus OpenID Connect quarkus-oidc extension also supports Bearer Token Authorization and uses smallrye-jwt to represent the bearer tokens as JsonWebToken . For more information, read the OIDC Bearer token authentication guide. OpenID Connect extension has to be used if the Quarkus application needs to authenticate the users using OIDC Authorization Code Flow. For more information, see OIDC code flow mechanism for protecting web applications
|
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 11+ がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.3
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
クイックスタート
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、すぐに完成した例に飛んでも構いません。
Git リポジトリーのクローンを作成: git clonehttps://github.com/quarkusio/quarkus-quickstarts.git
、または アーカイブ をダウンロードします。
The solution is located in the security-jwt-quickstart
directory.
Maven プロジェクトの作成
まず、以下のコマンドで新規プロジェクトを作成します:
Windowsユーザーの場合:
-
If using cmd, (don’t use backward slash
\
and put everything on the same line) -
If using Powershell, wrap
-D
parameters in double quotes e.g."-DprojectArtifactId=security-jwt-quickstart"
このコマンドは、RESTエンドポイントを持つMavenプロジェクトを生成し、MicroProfile JWT RBAC サポートを含む smallrye-jwt
エクステンションをインポートします。
すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに smallrye-jwt
エクステンションを追加することができます。
quarkus extension add 'smallrye-jwt,smallrye-jwt-build'
./mvnw quarkus:add-extension -Dextensions='smallrye-jwt,smallrye-jwt-build'
./gradlew addExtension --extensions='smallrye-jwt,smallrye-jwt-build'
これにより、 pom.xml
に以下が追加されます:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-jwt</artifactId>
</dependency>
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-smallrye-jwt-build</artifactId>
</dependency>
implementation("io.quarkus:quarkus-smallrye-jwt")
implementation("io.quarkus:quarkus-smallrye-jwt-build")
Jakarta REST リソースの調査
RESTエンドポイントを src/main/java/org/acme/security/jwt/TokenSecuredResource.java
に以下の内容で作成します。
package org.acme.security.jwt;
import java.security.Principal;
import jakarta.annotation.security.PermitAll;
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.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;
}
}
1 | ここでは、java.security.PrincipalのエクステンションであるJsonWebTokenインターフェイスを注入しています。これは、現在の認証済みトークンに関連するクレームへのアクセスを提供する、java.security.Principalインターフェースの拡張です。 |
2 | @PermitAll は、JSR 250 の一般的なセキュリティーアノテーションであり、認証されているかどうかに関係なく、特定のエンドポイントにすべての呼び出し元がアクセスできることを示します。 |
3 | ここでは、Jakarta REST SecurityContext を注入して呼び出しのセキュリティ状態を検査し、 getResponseString() 関数を使用して応答文字列を入力しています。 |
4 | ここでは、リクエストのユーザー/呼び出し元の Principal を null と照合して、呼び出しが安全でないかどうかを確認します。 |
5 | ここでは、JsonWebToken が現在の Principal を表しているため、Principal と JsonWebToken が同じ名前であることを確認します。 |
6 | ここで、Principal の名前を取得します。 |
7 | 構築した応答では、呼び出し元の名前、リクエスト SecurityContext の isSecure() と getAuthenticationScheme() の状態、null 以外の JsonWebToken が挿入されたかどうかを利用します。 |
アプリケーションの実行
これで、アプリケーションを実行する準備が整いました。以下を使用してください:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
次のような出力が得られるはずです:
[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, resteasy-reactive, resteasy-reactive-jackson, security, smallrye-context-propagation, smallrye-jwt, vertx, vertx-web]
REST エンドポイントが実行されているので、curl のようなコマンドラインツールを使ってアクセスすることができます。
$ curl http://127.0.0.1:8080/secured/permit-all; echo
hello + anonymous, isHttps: false, authScheme: null, hasJWT: false
このリクエストではJWTを設定していませんので、エンドポイントから見たセキュリティーステートがあるとは期待できず、レスポンスもそれに沿ったものとなっています。
-
ユーザー名は anonymous (匿名) です。
-
isHttps は https を使用しないので false です。
-
authScheme は null です。
-
hasJWTは false です。
Ctrl-Cを使用してQuarkusサーバーを停止します。
では実際に何かをセキュア化してみましょう。下記の新しいエンドポイントメソッド helloRolesAllowed
を見てみましょう。
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.JsonWebToken;
@Path("/secured")
@RequestScoped
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;
}
}
1 | ここでは、JsonWebToken を挿入します。 |
2 | この新しいエンドポイントは /secured/roles-allowed に存在します。 |
3 | @RolesAllowed は、"User" または "Admin" ロールが割り当てられている場合は呼び出し元が特定のエンドポイントにアクセスできることを示す JSR 250 の一般的なセキュリティーアノテーションです。 |
4 | ここでは、hello メソッドと同じ方法で応答を作成しますが、挿入された JsonWebToken を直接呼び出すことで JWT birthdate クレームの値を追加します。 |
TokenSecuredResource
にこの追加を行った後 、 ./mvnw compile quarkus:dev
コマンドを再実行し、次のように curl -v http://127.0.0.1:8080/secured/roles-allowed ; echo
を使用して、新しいエンドポイントへのアクセスを試行してみてください。
出力は以下のようになるはずです:
$ curl -v http://127.0.0.1:8080/secured/roles-allowed; echo
* 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
Not authorized
素晴らしい、リクエストでJWTを提供していないので、エンドポイントにアクセス出来ないはずであり、アクセス出来ませんでした。その代わり、HTTP 401 Unauthorizedエラーを受け取りました。エンドポイントにアクセスするには、有効なJWTを取得し、渡す必要があります。1)JWTを検証する方法に関する情報を持つSmallRye JWTエクステンションを設定する、2)適切なクレームを持つ一致するJWTを生成する、の2つのステップがあります。
SmallRye JWT エクステンションセキュリティー情報の設定
次の内容で security-jwt-quickstart/src/main/resources/application.properties
を作成します。
mp.jwt.verify.publickey.location=publicKey.pem (1)
mp.jwt.verify.issuer=https://example.com/issuer (2)
quarkus.native.resources.includes=publicKey.pem (3)
1 | 公開鍵の場所は、クラスパスのpublicKey.pemの場所を指すように設定しています。この鍵は、パートB 公開鍵の追加 で追加します。 |
2 | 発行者を URL 文字列 https://example.com/issuer に設定しています。 |
3 | ネイティブ実行可能ファイルのリソースとして公開鍵を含めています。 |
公開鍵の追加
JWT仕様 では、使用できるJWTのセキュリティレベルを様々に定義しています。 MicroProfile JWT RBAC 仕様は、RSA-256署名アルゴリズムで署名されたJWTを要求しています。これには、RSA公開鍵ペアが必要です。RESTエンドポイントサーバー側では、リクエストとともに送信されるJWTを検証するために使用するRSA公開鍵の場所を設定する必要があります。先に設定した mp.jwt.verify.publickey.location=publicKey.pem
の設定では、公開鍵がクラスパスで publicKey.pem
として利用可能であることを想定しています。これを実現するために、次の内容を security-jwt-quickstart/src/main/resources/publicKey.pem
ファイルにコピーします。
-----BEGIN PUBLIC KEY-----
MIIBIjANBgkqhkiG9w0BAQEFAAOCAQ8AMIIBCgKCAQEAlivFI8qB4D0y2jy0CfEq
Fyy46R0o7S8TKpsx5xbHKoU1VWg6QkQm+ntyIv1p4kE1sPEQO73+HY8+Bzs75XwR
TYL1BmR1w8J5hmjVWjc6R2BTBGAYRPFRhor3kpM6ni2SPmNNhurEAHw7TaqszP5e
UF/F9+KEBWkwVta+PZ37bwqSE4sCb1soZFrVz/UT/LF4tYpuVYt3YbqToZ3pZOZ9
AX2o1GCG3xwOjkc4x0W7ezbQZdC9iftPxVHR8irOijJRRjcPDtA6vPKpzLl6CyYn
sIYPd99ltwxTHjr3npfv/3Lw50bAkbT4HeLFxTx4flEoZLKO/g0bAoV2uqBhkA9x
nQIDAQAB
-----END PUBLIC KEY-----
JWT の生成
多くの場合、 Keycloak のようなIDマネージャからJWTを取得しますが、このクイックスタートでは、 smallrye-jwt
が提供するJWT生成APIを使用して独自に生成することにします。詳細は、SmallRye JWTでJWTトークンを生成 を参照してください。
次のリストからコードを取得し、security-jwt-quickstart/src/test/java/org/acme/security/jwt/GenerateToken.java
に配置します。
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;
public class GenerateToken {
/**
* Generate 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);
}
}
1 | iss クレームは JWT の発行者です。トークンが有効であると認められるためには、これがサーバー側の mp.jwt.verify.issuer と一致する必要があります。 |
2 | upn クレームは、MicroProfile JWT RBAC 仕様で、コンテナーセキュリティー API を介して表示される Principal に使用する優先クレームとして定義されています。 |
3 | group クレームは、JWT ベアラーに関連付けられたグループとトップレベルのロールを提供します。 |
4 | birthday クレームです。機密性の高いクレームと見なすことができるため、クレームの暗号化を検討したくなるかもしれません。 SmallRye JWT を使用した JWT トークンの生成 を参照してください。 |
このコードが機能するには、TokenSecuredResource アプリケーションにある公開鍵に対応する RSA 秘密鍵のコンテンツが必要であることに注意してください。次の PEM コンテンツを取得し、security-jwt-quickstart/src/test/resources/privateKey.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-----
smallrye.jwt.sign.key.location
プロパティーを使用して、この秘密署名鍵を指します。
OpenSSL を使用した鍵の生成
OpenSSL コマンドラインツールを使用して、公開鍵と秘密鍵のペアを生成することもできます。 鍵を生成するための openssl コマンド
秘密鍵を生成して PKCS#8 形式に変換するには、追加の手順が必要です。 秘密鍵を変換するための openssl コマンド
このクイックスタートで使用される鍵の代わりに、生成された鍵のペアを使用できます。 |
これで、TokenSecuredResource
エンドポイントで使用する JWT を生成できます。これを行うには、次のコマンドを実行します。
$ mvn exec:java -Dexec.mainClass=org.acme.security.jwt.GenerateToken -Dexec.classpathScope=test -Dsmallrye.jwt.sign.key.location=privateKey.pem
eyJraWQiOiJcL3ByaXZhdGVLZXkucGVtIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJqZG9lLXVzaW5nLWp3dC1yYmFjIiwiYXVkIjoidXNpbmctand0LXJiYWMiLCJ1cG4iOiJqZG9lQHF1YXJrdXMuaW8iLCJiaXJ0aGRhdGUiOiIyMDAxLTA3LTEzIiwiYXV0aF90aW1lIjoxNTUxNjU5Njc2LCJpc3MiOiJodHRwczpcL1wvcXVhcmt1cy5pb1wvdXNpbmctand0LXJiYWMiLCJyb2xlTWFwcGluZ3MiOnsiZ3JvdXAyIjoiR3JvdXAyTWFwcGVkUm9sZSIsImdyb3VwMSI6Ikdyb3VwMU1hcHBlZFJvbGUifSwiZ3JvdXBzIjpbIkVjaG9lciIsIlRlc3RlciIsIlN1YnNjcmliZXIiLCJncm91cDIiXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamRvZSIsImV4cCI6MTU1MTY1OTk3NiwiaWF0IjoxNTUxNjU5Njc2LCJqdGkiOiJhLTEyMyJ9.O9tx_wNNS4qdpFhxeD1e7v4aBNWz1FCq0UV8qmXd7dW9xM4hA5TO-ZREk3ApMrL7_rnX8z81qGPIo_R8IfHDyNaI1SLD56gVX-NaOLS2OjfcbO3zOWJPKR_BoZkYACtMoqlWgIwIRC-wJKUJU025dHZiNL0FWO4PjwuCz8hpZYXIuRscfFhXKrDX1fh3jDhTsOEFfu67ACd85f3BdX9pe-ayKSVLh_RSbTbBPeyoYPE59FW7H5-i8IE-Gqu838Hz0i38ksEJFI25eR-AJ6_PSUD0_-TV3NjXhF3bFIeT4VSaIZcpibekoJg0cQm-4ApPEcPLdgTejYHA-mupb8hSwg
JWT 文字列は Base64 URL でエンコードされた文字列で、'.' で区切られた 3 つのパートで構成されています。最初のパートは JWT ヘッダー、2 つ目のパートは JWT クレーム、3 つ目のパートは JWT シグネチャーです。
/secured/roles-allowed へのセキュリティーで保護されたアクセス
これを使用して、/secured/roles-allowed エンドポイントにセキュリティーで保護されたリクエストを作成しましょう。Quarkus サーバーが引き続き開発モードで実行されていることを確認してから、次のコマンドを実行し、前の手順で生成された自分の JWT バージョンを使用していることを確認します。
curl -H "Authorization: Bearer eyJraWQiOiJcL3ByaXZhdGVLZXkucGVtIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJqZG9lLXVzaW5nLWp3dC1yYmFjIiwiYXVkIjoidXNpbmctand0LXJiYWMiLCJ1cG4iOiJqZG9lQHF1YXJrdXMuaW8iLCJiaXJ0aGRhdGUiOiIyMDAxLTA3LTEzIiwiYXV0aF90aW1lIjoxNTUxNjUyMDkxLCJpc3MiOiJodHRwczpcL1wvcXVhcmt1cy5pb1wvdXNpbmctand0LXJiYWMiLCJyb2xlTWFwcGluZ3MiOnsiZ3JvdXAyIjoiR3JvdXAyTWFwcGVkUm9sZSIsImdyb3VwMSI6Ikdyb3VwMU1hcHBlZFJvbGUifSwiZ3JvdXBzIjpbIkVjaG9lciIsIlRlc3RlciIsIlN1YnNjcmliZXIiLCJncm91cDIiXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamRvZSIsImV4cCI6MTU1MTY1MjM5MSwiaWF0IjoxNTUxNjUyMDkxLCJqdGkiOiJhLTEyMyJ9.aPA4Rlc4kw7n_OZZRRk25xZydJy_J_3BRR8ryYLyHTO1o68_aNWWQCgpnAuOW64svPhPnLYYnQzK-l2vHX34B64JySyBD4y_vRObGmdwH_SEufBAWZV7mkG3Y4mTKT3_4EWNu4VH92IhdnkGI4GJB6yHAEzlQI6EdSOa4Nq8Gp4uPGqHsUZTJrA3uIW0TbNshFBm47-oVM3ZUrBz57JKtr0e9jv0HjPQWyvbzx1HuxZd6eA8ow8xzvooKXFxoSFCMnxotd3wagvYQ9ysBa89bgzL-lhjWtusuMFDUVYwFqADE7oOSOD4Vtclgq8svznBQ-YpfTHfb9QEcofMlpyjNA" http://127.0.0.1:8080/secured/roles-allowed; echo
$ curl -H "Authorization: Bearer eyJraWQ..." http://127.0.0.1:8080/secured/roles-allowed; echo
hello + jdoe@quarkus.io, isHttps: false, authScheme: Bearer, hasJWT: true, birthdate: 2001-07-13
成功! これで、以下が得られます
-
jdoe@quarkus.io という非匿名の発信者名
-
ベアラーの認証スキーム
-
非 null の JsonWebToken
-
birthdate クレームの値
JsonWebToken とクレーム挿入の使用
さて、安全なRESTエンドポイントにアクセスするためにJWTを生成できるようになったので、 JsonWebToken
インターフェースとJWTクレームを使ってさらに何ができるかを見てみましょう。 org.eclipse.microprofile.jwt.JsonWebToken
インターフェースは java.security.Principal
インターフェースを拡張したもので、実際には前回使用した jakarta.ws.rs.core.SecurityContext#getUserPrincipal()
呼び出しによって返されるオブジェクトの型です。つまり、CDIを使用せず、RESTコンテナ SecurityContext
にアクセスできるコードは、 SecurityContext#getUserPrincipal()
をキャストすることで、呼び出し元の JsonWebToken
インターフェースを取得することができます。
JsonWebToken
インタフェースは、基礎となる JWT のクレームにアクセスするためのメソッドを定義します。mp-jwt}仕様で要求される一般的なクレームと、JWTに存在しうる任意のクレームに対するアクセッサを提供します。
すべてのJWTクレームも注入することができます。 TokenSecuredResource
を、注入された birthdate
のクレームを使う別のエンドポイント /secured/roles-allowed-admin で拡張してみましょう ( 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
public class TokenSecuredResource {
@Inject
JsonWebToken jwt; (1)
@Inject
@Claim(standard = Claims.birthdate)
String birthdate; (2)
@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; (3)
}
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;
}
}
1 | ここでは、JsonWebToken を挿入します。 |
2 | ここでは、birthday クレームを String として挿入します。これが @RequestScoped スコープが必要になった理由です。 |
3 | ここでは、挿入された birthday クレームを使用して、最終的な応答を作成します。 |
次に、トークンを再度生成して実行します。
curl -H "Authorization: Bearer eyJraWQiOiJcL3ByaXZhdGVLZXkucGVtIiwidHlwIjoiSldUIiwiYWxnIjoiUlMyNTYifQ.eyJzdWIiOiJqZG9lLXVzaW5nLWp3dC1yYmFjIiwiYXVkIjoidXNpbmctand0LXJiYWMiLCJ1cG4iOiJqZG9lQHF1YXJrdXMuaW8iLCJiaXJ0aGRhdGUiOiIyMDAxLTA3LTEzIiwiYXV0aF90aW1lIjoxNTUxNjUyMDkxLCJpc3MiOiJodHRwczpcL1wvcXVhcmt1cy5pb1wvdXNpbmctand0LXJiYWMiLCJyb2xlTWFwcGluZ3MiOnsiZ3JvdXAyIjoiR3JvdXAyTWFwcGVkUm9sZSIsImdyb3VwMSI6Ikdyb3VwMU1hcHBlZFJvbGUifSwiZ3JvdXBzIjpbIkVjaG9lciIsIlRlc3RlciIsIlN1YnNjcmliZXIiLCJncm91cDIiXSwicHJlZmVycmVkX3VzZXJuYW1lIjoiamRvZSIsImV4cCI6MTU1MTY1MjM5MSwiaWF0IjoxNTUxNjUyMDkxLCJqdGkiOiJhLTEyMyJ9.aPA4Rlc4kw7n_OZZRRk25xZydJy_J_3BRR8ryYLyHTO1o68_aNWWQCgpnAuOW64svPhPnLYYnQzK-l2vHX34B64JySyBD4y_vRObGmdwH_SEufBAWZV7mkG3Y4mTKT3_4EWNu4VH92IhdnkGI4GJB6yHAEzlQI6EdSOa4Nq8Gp4uPGqHsUZTJrA3uIW0TbNshFBm47-oVM3ZUrBz57JKtr0e9jv0HjPQWyvbzx1HuxZd6eA8ow8xzvooKXFxoSFCMnxotd3wagvYQ9ysBa89bgzL-lhjWtusuMFDUVYwFqADE7oOSOD4Vtclgq8svznBQ-YpfTHfb9QEcofMlpyjNA" http://127.0.0.1:8080/secured/roles-allowed-admin; echo
$ curl -H "Authorization: Bearer eyJraWQ..." http://127.0.0.1:8080/secured/roles-allowed-admin; echo
hello + jdoe@quarkus.io, isHttps: false, authScheme: Bearer, hasJWT: true, birthdate: 2001-07-13
アプリケーションのパッケージ化と実行
いつものように、アプリケーションは以下の方法でパッケージ化されます。
quarkus build
./mvnw install
./gradlew build
そして、java -jar target/quarkus-app/quarkus-run.jar
を使って実行されます。
$ java -jar target/quarkus-app/quarkus-run.jar
2019-03-28 14:27:48,839 INFO [io.quarkus] (main) Quarkus 3.4.1 started in 0.796s. Listening on: http://[::]:8080
2019-03-28 14:27:48,841 INFO [io.quarkus] (main) Installed features: [cdi, resteasy-reactive, resteasy-reactive-jackson, security, smallrye-jwt]
次のようにネイティブ実行可能ファイルを生成することもできます。
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.package.type=native
[INFO] Scanning for projects...
...
[security-jwt-quickstart-runner:25602] universe: 493.17 ms
[security-jwt-quickstart-runner:25602] (parse): 660.41 ms
[security-jwt-quickstart-runner:25602] (inline): 1,431.10 ms
[security-jwt-quickstart-runner:25602] (compile): 7,301.78 ms
[security-jwt-quickstart-runner:25602] compile: 10,542.16 ms
[security-jwt-quickstart-runner:25602] image: 2,797.62 ms
[security-jwt-quickstart-runner:25602] write: 988.24 ms
[security-jwt-quickstart-runner:25602] [total]: 43,778.16 ms
[INFO] ------------------------------------------------------------------------
[INFO] BUILD SUCCESS
[INFO] ------------------------------------------------------------------------
[INFO] Total time: 51.500 s
[INFO] Finished at: 2019-03-28T14:30:56-07:00
[INFO] ------------------------------------------------------------------------
$ ./target/security-jwt-quickstart-runner
2019-03-28 14:31:37,315 INFO [io.quarkus] (main) Quarkus 0.12.0 started in 0.006s. Listening on: http://[::]:8080
2019-03-28 14:31:37,316 INFO [io.quarkus] (main) Installed features: [cdi, resteasy-reactive, resteasy-reactive-jackson, security, smallrye-jwt]
ソリューションの探索
The solution repository located in the security-jwt-quickstart
directory contains all the versions we have worked through in this quickstart guide as well as some additional endpoints that illustrate subresources with injection of JsonWebToken
s and their claims into those using the CDI APIs. We suggest that you check out the quickstart solutions and explore the security-jwt-quickstart
directory to learn more about the SmallRye JWT extension features.
リファレンスガイド
サポートされている注入スコープ
org.eclipse.microprofile.jwt.JsonWebToken
が注入される場合、@ApplicationScoped
、@Singleton
、および @RequestScoped
の外部 Bean 注入スコープがすべてサポートされます。また、現在のトークンが示されていることを確認するために、JsonWebToken
の @RequestScoped
スコープが適用されます。
ただし、個々のトークンクレームが 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;
}
注入された JsonWebToken
を使用して個々のクレームにアクセスすることもできます。その場合、@RequestScoped
を設定する必要はありません。
詳細については、 MP JWT CDI 注入要件 を参照してください。
サポートされている公開鍵形式
公開鍵には、優先順位に従って指定された次のいずれかの形式が適用さされます。
-
Public Key Cryptography Standards #8 (PKCS#8) PEM
-
JSON Web Key (JWK)
-
JSON Web Key Set (JWKS)
-
JSON Web Key (JWK) Base64 URL エンコード
-
JSON Web Key Set (JWKS) Base64 URL エンコード
検証鍵の処理
非対称 RSA または楕円曲線 (EC) 鍵を使用してトークンの署名を検証する必要がある場合は、mp.jwt.verify.publickey.location
プロパティーを使用してローカルまたはリモートの検証鍵を参照します。
mp.jwt.verify.publickey.algorithm
を使用して検証アルゴリズムをカスタマイズします (デフォルトは RS256
)。たとえば、EC 鍵を操作する場合は ES256
に設定します。
対称秘密鍵を使用してトークン署名を検証する必要がある場合は、JSON Web 鍵 (JWK) または JSON Web 鍵セット (JWK セット) 形式のいずれかを使用して、この秘密鍵を表す必要があります。以下はその例です。
{
"keys": [
{
"kty":"oct",
"kid":"secretKey",
"k":"AyM1SysPpbyDfgZld3umj1qzKObwVMkoqQ-EstJQLr_T-1qS0gZH75aKtMN3Yj0iPS4hcgUuTwjAzZr1Z9CAow"
}
]
}
この秘密鍵 JWK も、smallrye.jwt.verify.key.location
で参照する必要があります。smallrye.jwt.verify.algorithm
は HS256
/HS384
/HS512
に設定する必要があります。
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);
これを使用して、トークンの検証または復号化の方法をカスタマイズすることもできます。たとえば、ローカルの SecretKey
を指定できます。
import javax.crypto.SecretKey;
import jakarta.ws.rs.GET;
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 {
@Inject JWTParser parser;
private String secret = "AyM1SysPpbyDfgZld3umj1qzKObwVMko";
@GET
@Produces("text/plain")
public Response getUserName(@CookieParam("jwt") String jwtCookie) {
Response response = null;
if (jwtCookie == null) {
// Create a JWT token signed using the 'HS256' algorithm
String newJwtCookie = Jwt.upn("Alice").signWithSecret(secret);
// or create a JWT token encrypted 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();
}
}
}
また、 quarkus-smallrye-jwt
が提供する HTTP
サポート無しで JWTParser
を使用する方法については、SmallRye JWT を直接追加する方法 を参照してください。
トークン復号化
アプリケーションが暗号化されたクレームや暗号化・内部署名付きクレームを持つトークンを受け入れる必要がある場合は、必要な作業は、復号化キーを指す smallrye.jwt.decrypt.key.location
を設定することだけです。
この鍵プロパティのみが設定されている場合、受信トークンには暗号化クレームのみが含まれることが期待されます。 mp.jwt.verify.publickey
または mp.jwt.verify.publickey.location
のいずれかの検証プロパティも設定されている場合、受信トークンには暗号化・内部署名付きトークンが含まれることが期待されます。
SmallRye JWT を使用した JWT トークンの生成 を参照し、暗号化または内部署名されてから暗号化されたトークンをすぐに生成する方法を確認してください。
カスタムファクトリー
io.smallrye.jwt.auth.principal.DefaultJWTCallerPrincipalFactory
は、デフォルトで JWT トークンを解析および検証し、それらを JsonWebToken
プリンシパルに変換するために使用されます。設定セクションにリストされている MP JWT
および smallrye-jwt
プロパティーを使用して、JWT トークンを検証およびカスタマイズします。
たとえば、ファイアウォールによってすでに検証されているトークンの再検証を回避するために独自のファクトリーを提供する必要がある場合は、META-INF/services/io.smallrye.jwt.auth.principal.JWTCallerPrincipalFactory
リソースを提供すして ServiceLoader
メカニズムを使用するか、単純に次のような Alternative
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());
}
}
}
Blocking calls
quarkus-smallrye-jwt
extension uses SmallRye JWT library which is currently not reactive.
What it means from the perspective of quarkus-smallrye-jwt
which operates as part of the reactive Quarkus security architecture, is that an IO thread entering the SmallRye JWT verification or decryption code might block in one of the following cases:
-
Default key resolver refreshes
JsonWebKey
set containing the keys which involves a remote call to the OIDC endpoint -
Custom key resolver such as
AWS Application Load Balancer
(ALB
) key resolver, resolves the keys against the AWS ALB key endpoint using the current token’s key identifier header value
In such cases, if the connections are slow, for example, it may take more than 3 seconds to get a response from the key endpoint, the current event loop thread will most likely block.
To prevent it, set quarkus.smallrye-jwt.blocking-authentication=true
.
トークンの伝播
下流サービスへのベアラアクセストークンの伝搬については、 トークンの伝搬 の項を参照してください。
テスト
Wiremock
If you configure mp.jwt.verify.publickey.location
to point to HTTPS or HTTP based JsonWebKey (JWK) set then you can use the same approach as described in the OpenID Connect Bearer Token Integration testing Wiremock
section but only change the application.properties
to use MP JWT configuration properties instead:
# 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
Keycloak
If you work with Keycloak and configure mp.jwt.verify.publickey.location
to point to HTTPS or HTTP based JsonWebKey (JWK) set then you can use the same approach as described in the OpenID Connect Bearer Token Integration testing Keycloak section but only change the application.properties
to use MP JWT configuration properties instead:
# 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
Keycloakが発行したトークンは、レルムエンドポイントアドレスが iss
(発行者)クレームに設定されていることに注目してください。
QuarkusアプリケーションがDockerコンテナで実行されている場合、DevServices for Keycloakによって起動されたKeycloak dockerコンテナとネットワークインターフェースを共有し、QuarkusアプリケーションとKeycloakは内部の共有Dockerネットワークを通じて互いに通信することができます。
そのような場合は、代わりに以下のような設定にしてください。
# keycloak.url is set by DevServices for Keycloak,
# Quarkus will access it via 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}
ローカル公開鍵
You can use the same approach as described in the OpenID Connect Bearer Token Integration testing Local Public Key
section but only change the application.properties
to use MP JWT configuration properties instead:
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
TestSecurity アノテーション
以下の依存関係を追加します。
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-security-jwt</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.quarkus:quarkus-test-security-jwt")
次のようなテストコードを作成します。
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"));
}
}
ここで、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");
}
}
@TestSecurity
アノテーションは常に使用する必要があり、その user
プロパティーは JsonWebToken.getName()
として返され、roles
プロパティーは JsonWebToken.getGroups()
として返されることに注意してください。@JwtSecurity
アノテーションはオプションであり、追加のトークンクレームを設定するために使用できます。
これは、同じセキュリティ設定のセットを複数のテストメソッドで使用する必要がある場合に特に便利です。 |
ログでエラーを確認する方法
トークンの検証または復号化エラーの詳細を確認するには、io.quarkus.smallrye.jwt.runtime.auth.MpJwtValidator
TRACE
レベルのログを有効にしてください。
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
プロアクティブ認証
If you’d like to skip the token verification when the public endpoint methods are invoked, disable the proactive authentication.
トークンの検証が実行されていない場合、パブリックメソッドで挿入された JsonWebToken
にアクセスできないことに注意してください。
SmallRye JWT を直接追加する方法
JWTParserでJsonWebTokenを解析・検証 するには、以下のような状況では、 quarkus-smallrye-jwt
の代わりに smallrye-jwt
を直接使用します:
-
HTTP
をサポートしていないQuarkusエクステンション、例えばQuarkus GRPC
などを使用している場合。 -
You provide an extension-specific
HTTP
, the support of which conflicts with the support of those offered byquarkus-smallrye-jwt
andVert.x HTTP
, such asQuarkus AWS Lambda
.
まず、 smallrye-jwt
の依存関係を追加することから始めます:
<dependency>
<groupId>io.smallrye</groupId>
<artifactId>smallrye-jwt</artifactId>
</dependency>
implementation("io.smallrye:smallrye-jwt")
さらに、application.properties
を更新して、smallrye-jwt
によって提供されるすべての CDI プロデューサーを次のように含めます。
quarkus.index-dependency.smallrye-jwt.group-id=io.smallrye
quarkus.index-dependency.smallrye-jwt.artifact-id=smallrye-jwt
設定リファレンス
Quarkus の設定
ビルド時に固定される設定プロパティ - その他の設定プロパティは実行時にオーバーライド可能です。
型 |
デフォルト |
|
---|---|---|
The MP-JWT configuration object Environment variable: Show more |
boolean |
|
The name of the Environment variable: Show more |
string |
|
Enable this property if fetching the remote keys can be a time-consuming operation. Do not enable it if you use the local keys. Environment variable: Show more |
boolean |
|
Always create HTTP 401 challenge, even for requests containing no authentication credentials. JWT authentication mechanism will return HTTP 401 when an authentication challenge is required. However if it is used alongside one of the interactive authentication mechanisms then returning HTTP 401 to the users accessing the application from a browser may not be desired. If you prefer you can request that JWT authentication mechanism does not create a challenge in such cases by setting this property to 'true'. Environment variable: Show more |
boolean |
|
MicroProfile JWT の設定
プロパティ名e | デフォルト | 説明 |
---|---|---|
|
|
|
|
|
Config プロパティーを使用すると、公開鍵の外部または内部の場所を指定できます。値は相対パスまたは URL の場合があります。値が HTTPS ベースの JWK セットを指している場合、ネイティブモードで機能するには、 |
|
|
署名アルゴリズム。 |
|
|
Config プロパティーを使用すると、秘密復号化鍵の外部または内部の場所を指定できます。 |
|
|
Config プロパティーは、サーバーが有効として受け入れる JWT の |
|
|
トークン |
|
|
トークンの有効期限と年齢確認時に使用されるクロックスキュー(秒)。トークンの有効期限切れ後、現在時刻がこのプロパティで指定された秒数以内であれば、期限切れのトークンは受理されます。デフォルト値は60秒です。 |
|
|
トークン発行時刻 |
|
|
|
|
|
トークンを含む Cookie の名前。このプロパティーは、 |
追加の SmallRye JWT 設定
SmallRye JWTには、トークン処理をカスタマイズするために使用できる、より多くのプロパティーが用意されています。
プロパティ名e | デフォルト | 説明 |
---|---|---|
|
|
公開鍵と秘密鍵の両方を指すことができる検証鍵の場所。秘密鍵は JWK 形式でのみ使用できます。このプロパティーが設定されている場合、'mp.jwt.verify.publickey.location' は無視されることに注意してください。 |
|
署名アルゴリズム。このプロパティーは、 |
|
|
|
このプロパティーを |
|
|
By default, PEM, JWK or JWK key sets can be read from the local file system or fetched from URIs as required by MicroProfile JWT specification. Set this property to |
|
|
検証鍵の検証を緩和します。このプロパティーを |
|
|
このプロパティーが有効になっている場合、署名されたトークンには 'x5t' または 'x5t#S256' X509Certificatex5t 拇印ヘッダーが含まれている必要があります。この場合、検証鍵は JWK または PEM 証明書鍵形式でのみ使用できます。JWK 鍵には、'x5c' (Base64 でエンコードされた X509Certificate) プロパティーが設定されている必要があります。 |
|
|
|
|
|
Key cache size. Use this property, as well as |
|
|
Key cache entry time-to-live in minutes. Use this property, as well as |
|
|
Name of the cookie containing a token. This property will be effective only if |
|
|
|
|
|
|
|
|
鍵の識別子。設定されている場合、検証 JWK 鍵とすべての JWT トークンには、一致する |
|
|
JWT を使用するために発行できる最大秒数。事実上、JWT の有効期限と発行日との差はこの値を超えてはなりません。このプロパティーを正でない値に設定すると、トークンが有効な 'iat' (で発行された) クレームを持つための要件が緩和されます。 |
|
|
アプリケーションが名前を返す |
|
|
件名を含むクレームへのパス。これはトップレベルの JSON オブジェクトから始まり、複数のセグメントを含めることができます。各セグメントは JSON オブジェクト名のみを表します (例: |
|
|
現在のトークンに使用可能な標準またはカスタムの |
|
|
グループを含むクレームへのパス。これはトップレベルの JSON オブジェクトから始まり、複数のセグメントを含めることができます。各セグメントは JSON オブジェクト名のみを表します (例: |
|
|
複数のグループ値を含む可能性のある文字列を分割するためのセパレーター。これは、 |
|
|
このプロパティーを使用して、現在のトークンに使用可能な標準またはカスタムのグループクレームがない場合に、デフォルトのグループクレーム値を設定できます。 |
|
|
JWK キャッシュの更新間隔 (分単位)。 |
|
|
強制 JWK キャッシュ更新間隔 (分単位)。現在のトークンの |
|
|
有効期限を秒単位で指定します。デフォルトでは、現在時刻がトークンの有効期限から1分以内であれば、期限切れのトークンはまだ受け入れられます。このプロパティは非推奨です。代わりに |
|
|
トークン |
|
|
トークンに含める必要のあるクレームのコンマ区切りリスト。 |
|
|
Config property allows for an external or internal location of Private Decryption Key to be specified. This property is deprecated - use |
|
|
復号化アルゴリズム。 |
|
|
文字列として提供される復号化キー。 |
|
|
復号化キー識別子。設定されている場合、復号化 JWK キーとすべての JWT トークンには、一致する |
|
|
キーを |
|
|
すべてのホスト名を信頼します。キーを |
|
|
信頼できるホスト名のセット。キーを |
|
|
HTTP プロキシーホスト。 |
|
|
HTTP プロキシーポート。 |
|
|
|
|
|
|
|
キーストアのパスワード。 |
|
|
このプロパティーは、 |
|
|
このプロパティは、 |
|
|
このプロパティは、 |