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 エクステンションは、ベアラートークン認証にも対応しており、 smallrye-jwt を使用して、ベアラートークンを JsonWebToken として表します。
詳細については、 OIDCベアラートークン認証 ガイドを参照してください。
Quarkus アプリケーションで OIDC 認可コードフローを使用してユーザーを認証する必要がある場合は、OpenID Connect エクステンションを使用する必要があります。
詳細については、 Webアプリケーションを保護するためのOIDCコードフロー メカニズムを参照してください。
|
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 17+がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.8
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
クイックスタート
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、すぐに完成した例に飛んでも構いません。
Git リポジトリーのクローンを作成: git clonehttps://github.com/quarkusio/quarkus-quickstarts.git
、または アーカイブ をダウンロードします。
ソリューションは security-jwt-quickstart
ディレクトリ にあります。
Maven プロジェクトの作成
まず、以下のコマンドで新規プロジェクトを作成します:
Windowsユーザーの場合:
-
cmdを使用する場合、(バックスラッシュ
\
を使用せず、すべてを同じ行に書かないでください)。 -
Powershellを使用する場合は、
-D
パラメータを二重引用符で囲んでください。例:"-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 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;
}
}
1 | ここでは、現在認証されているトークンに関連付けられたクレームへのアクセスを提供する java.security.Principal インターフェイスのエクステンションである JsonWebToken インターフェイスを挿入します。 |
2 | @PermitAllは、Jakarta共通セキュリティアノテーションで、認証されているかどうかにかかわらず、指定されたエンドポイントにはどの呼び出し元からもアクセスできることを示します。 |
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, rest, rest-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.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;
}
}
1 | ここでは、JsonWebToken を挿入します。 |
2 | この新しいエンドポイントは /secured/roles-allowed に存在します。 |
3 | @RolesAllowed is a Jakarta common security annotation that indicates that the given endpoint is accessible by a caller if
they have either a "User" or "Admin" role assigned. |
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
素晴らしいですね。リクエストに JWT トークンを提供していないため、エンドポイントにはアクセスできないはずであり、実際にアクセスできませんでした。代わりに HTTP 401 Unauthorized エラーを受け取りました。エンドポイントにアクセスするためには、有効な JWT を取得して渡す必要があります。これには 2 つのステップがあります。1) SmallRye JWT エクステンションに JWT の検証方法に関する情報を設定し、2) 適切なクレームを持つ適合する JWT を生成します。
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 | We are setting public key location to point to a classpath publicKey.pem location. We will add this key in part 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 のクレームにアクセスするためのメソッドを定義します。これは、JWT に存在する可能性のある MicroProfile JWT RBAC 仕様および任意のクレームで必要な一般的クレームのアクセッサを提供します。。
すべての JWT クレームを挿入することもできます。TokenSecuredResource
を別のエンドポイント /secured/roles-allowed-admin で拡張してみましょう。これは、(JsonWebToken
から取得するのではなく) 挿入された birthdate
クレームを使用します。
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;
}
}
1 | RequestScoped scope is required to support an injection of the birthday claim as String . |
2 | ここでは、JsonWebToken を挿入します。 |
3 | ここでは、birthday クレームを String として挿入します。これが @RequestScoped スコープが必要になった理由です。 |
4 | ここでは、挿入された 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.15.1 started in 0.796s. Listening on: http://[::]:8080
2019-03-28 14:27:48,841 INFO [io.quarkus] (main) Installed features: [cdi, rest, rest-jackson, security, smallrye-jwt]
次のようにネイティブ実行可能ファイルを生成することもできます。
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.native.enabled=true
[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, rest, rest-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
を指定できます。
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 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();
}
}
}
Please also see the How to Add SmallRye JWT directly section about using JWTParser
without the HTTP
support provided by quarkus-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());
}
}
}
ブロッキング呼出
quarkus-smallrye-jwt
エクステンションでは、現在リアクティブではない SmallRye JWT ライブラリを使用します。
`quarkus-smallrye-jwt`がリアクティブなQuarkusセキュリティ・アーキテクチャの一部として動作する観点からこれが意味することは 、 SmallRye JWT 検証または復号化コードに入るIOスレッドが、以下のいずれかのケースでブロックされる可能性があるということです:
-
デフォルトのキーリゾルバーが、OIDCエンドポイントへのリモートコールを伴うキーを含む
JsonWebKey
セットを更新します -
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.
これを防ぐには、 quarkus.smallrye-jwt.blocking-authentication=true
を設定します。
トークンの伝播
Please see the Token Propagation section about the Bearer access token propagation to the downstream services.
テスト
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
プロアクティブ認証
パブリックエンドポイントメソッド呼び出し時のトークン検証を省略したい場合は、 プロアクティブ認証 を無効にします。
トークンの検証が実行されていない場合、パブリックメソッドで挿入された JsonWebToken
にアクセスできないことに注意してください。
SmallRye JWT を直接追加する方法
To parse and verify JsonWebToken with JWTParser, use smallrye-jwt
instead of quarkus-smallrye-jwt
directly for the following situations:
-
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 の設定
ビルド時に固定される構成プロパティ - 他のすべての構成プロパティは実行時にオーバーライド可能
Configuration property |
型 |
デフォルト |
---|---|---|
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 の設定
プロパティ名 | デフォルト | 説明 |
---|---|---|
|
|
The |
|
|
Config プロパティーを使用すると、公開鍵の外部または内部の場所を指定できます。値は相対パスまたは URL の場合があります。値が HTTPS ベースの JWK セットを指している場合、ネイティブモードで機能するには、 |
|
|
署名アルゴリズム。 |
|
|
Config プロパティーを使用すると、秘密復号化鍵の外部または内部の場所を指定できます。 |
|
|
Config プロパティーは、サーバーが有効として受け入れる JWT の |
|
|
トークン |
|
|
トークンの有効期限と年齢確認時に使用されるクロックスキュー(秒)。トークンの有効期限切れ後、現在時刻がこのプロパティで指定された秒数以内であれば、期限切れのトークンは受理されます。デフォルト値は60秒です。 |
|
|
トークン発行時刻 |
|
|
|
|
|
トークンを含む Cookie の名前。このプロパティーは、 |
追加の SmallRye JWT 設定
SmallRye JWTには、トークン処理をカスタマイズするために使用できる、より多くのプロパティーが用意されています。
プロパティ名 | デフォルト | 説明 |
---|---|---|
|
|
公開鍵と秘密鍵の両方を指すことができる検証鍵の場所。秘密鍵は JWK 形式でのみ使用できます。このプロパティーが設定されている場合、'mp.jwt.verify.publickey.location' は無視されることに注意してください。 |
|
署名アルゴリズム。このプロパティーは、 |
|
|
|
このプロパティーを |
|
|
デフォルトでは、PEM、JWK、または JWK キーセットは、ローカルファイルシステムから読み取るか、MicroProfile JWT 仕様で要求される URI から取得できます。AWS Application Load Balancer の検証キー解決をサポートするには、このプロパティを |
|
|
検証鍵の検証を緩和します。このプロパティーを |
|
|
このプロパティーが有効になっている場合、署名されたトークンには 'x5t' または 'x5t#S256' X509Certificatex5t 拇印ヘッダーが含まれている必要があります。この場合、検証鍵は JWK または PEM 証明書鍵形式でのみ使用できます。JWK 鍵には、'x5c' (Base64 でエンコードされた X509Certificate) プロパティーが設定されている必要があります。 |
|
|
|
|
|
キー・キャッシュのサイズ。このプロパティは、 |
|
|
キー・キャッシュ・エントリーの有効期限を分単位で示します。このプロパティは、 |
|
|
トークンを含むクッキーの名前。このプロパティは、 |
|
|
|
|
|
|
|
|
鍵の識別子。設定されている場合、検証 JWK 鍵とすべての JWT トークンには、一致する |
|
|
JWT を使用するために発行できる最大秒数。事実上、JWT の有効期限と発行日との差はこの値を超えてはなりません。このプロパティーを正でない値に設定すると、トークンが有効な 'iat' (で発行された) クレームを持つための要件が緩和されます。 |
|
|
アプリケーションが名前を返す |
|
|
件名を含むクレームへのパス。これはトップレベルの JSON オブジェクトから始まり、複数のセグメントを含めることができます。各セグメントは JSON オブジェクト名のみを表します (例: |
|
|
現在のトークンに使用可能な標準またはカスタムの |
|
|
グループを含むクレームへのパス。これはトップレベルの JSON オブジェクトから始まり、複数のセグメントを含めることができます。各セグメントは JSON オブジェクト名のみを表します (例: |
|
|
複数のグループ値を含む可能性のある文字列を分割するためのセパレーター。これは、 |
|
|
このプロパティーを使用して、現在のトークンに使用可能な標準またはカスタムのグループクレームがない場合に、デフォルトのグループクレーム値を設定できます。 |
|
|
JWK キャッシュの更新間隔 (分単位)。 |
|
|
強制 JWK キャッシュ更新間隔 (分単位)。現在のトークンの |
|
|
有効期限を秒単位で指定します。デフォルトでは、現在時刻がトークンの有効期限から1分以内であれば、期限切れのトークンはまだ受け入れられます。このプロパティは非推奨です。代わりに |
|
|
トークン |
|
|
トークンに含める必要のあるクレームのコンマ区切りリスト。 |
|
|
設定プロパティでは、秘密復号鍵の外部または内部の場所を指定できます。このプロパティは非推奨です。 |
|
|
復号化アルゴリズム。 |
|
|
文字列として提供される復号化キー。 |
|
|
復号化キー識別子。設定されている場合、復号化 JWK キーとすべての JWT トークンには、一致する |
|
|
キーを |
|
|
すべてのホスト名を信頼します。キーを |
|
|
信頼できるホスト名のセット。キーを |
|
|
HTTP プロキシーホスト。 |
|
|
HTTP プロキシーポート。 |
|
|
|
|
|
|
|
キーストアのパスワード。 |
|
|
このプロパティーは、 |
|
|
このプロパティは、 |
|
|
このプロパティは、 |
|
|
|
Set this property to true to resolve the remote keys at the application startup. |