セキュリティーアーキテクチャー
概要
Red Hat build of Quarkus ドキュメントへのフィードバックの提供
エラーを報告したり、ドキュメントを改善したりするには、Red Hat Jira アカウントにログインし、課題を送信してください。Red Hat Jira アカウントをお持ちでない場合は、アカウントを作成するように求められます。
手順
- 次のリンクをクリックして チケットを作成します。
- Summary に課題の簡単な説明を入力します。
- Description に課題や機能拡張の詳細な説明を入力します。問題があるドキュメントのセクションへの URL も記載してください。
- Submit をクリックすると、課題が作成され、適切なドキュメントチームに転送されます。
第1章 Quarkus Security アーキテクチャー
Quarkus Security アーキテクチャーにはビルトイン認証メカニズムがいくつかあり、高度なカスタマイズが可能です。Quarkus で HTTP アプリケーションを保護するための主なメカニズムは、HttpAuthenticationMechanism
インターフェイスです。
1.1. Quarkus Security アーキテクチャーの概要
クライアントが HTTP リクエストを送信すると、Quarkus Security は、HttpAuthenticationMechanism
、IdentityProvider
、SecurityIdentityAugmentor
などのいくつかのビルトインコアコンポーネントと対話して、セキュリティーの認証と認可のオーケストレーションを行います。
連続セキュリティー検証プロセスの結果は、次の 3 つのうちのいずれかになります。
- HTTP リクエストが認証および認可され、Quarkus アプリケーションへのアクセスが許可されます。
-
HTTP リクエストの認証が失敗し、リクエスターは認証メカニズムに固有のチャレンジ (
401
エラー、再認証のための URL リダイレクト、その他カスタムの認証チャレンジレスポンスなど) を受信します。チャレンジレスポンスの実践的な例は、Quarkus の Security Tips and Tricks ガイドを参照してください。 - HTTP リクエストの認証が失敗し、リクエスターは Quarkus アプリケーションへのアクセスを拒否されます。
次の図は、Quarkus Security アーキテクチャーの詳細なプロセスフローを段階的に示しています。
図1.1 Quarkus Security アーキテクチャーとプロセスフロー

1.2. Quarkus Security アーキテクチャーのコアコンポーネント
1.2.1. HttpAuthenticationMechanism
Quarkus Security は、HttpAuthenticationMechanism
を使用して HTTP リクエストから認証情報を抽出し、それを IdentityProvider
に委譲して認証情報を SecurityIdentity
に変換します。たとえば、認証情報は Authorization
ヘッダー、クライアント HTTPS 証明書、または Cookie から取得できます。
Quarkus Security が認証リクエストを拒否すると、HttpAuthenticationMechanism
はクライアントに認証チャレンジを返します。チャレンジの種類は認証メカニズムにより異なります。たとえば、OIDC OpenID Connect (OIDC) 認可コードフローメカニズムを使用すると、リダイレクト URL が生成され、クライアントは認証のために OpenID Connect プロバイダーに返されます。
1.2.2. IdentityProvider
IdentityProvider
は認証情報を検証し、それをユーザー名、ロール、元の認証情報、およびその他の属性を持つ SecurityIdentity
にマッピングします。
認証されたリソースごとに SecurityIdentity
インスタンスを注入し、認証されたアイデンティティー情報を取得できます。
他のコンテキストでは、同じ情報またはその一部の並列表現を他にも持つことが可能です。たとえば、Jakarta REST の SecurityContext
や JSON Web Token (JWT) の JsonWebToken
などです。
詳細は、Quarkus の Identity providers ガイドを参照してください。
1.2.3. SecurityIdentityAugmentor
Quarkus Security はカスタマイズできるため、たとえば SecurityIdentity
に認可ロールを追加したり、1 つ以上の SecurityAugmentor
実装を登録して優先順位を付けたりすることができます。
登録された SecurityIdentityAugmentor
のインスタンスは、セキュリティー認証プロセスの最終段階で呼び出されます。詳細は、「Security Tips and Tricks」ガイドの Security Identity Customization セクションを参照してください。
1.3. サポート対象の認証メカニズム
Quarkus Security フレームワークは複数の認証メカニズムをサポートしており、それらを組み合わせることもできます。サポートされている認証メカニズムの一部は Quarkus に組み込まれていますが、エクステンションの追加が必要なものもあります。
Quarkus のセキュリティー認証とサポートされているメカニズムおよびプロトコルの詳細は、Quarkus の認証メカニズム ガイドを参照してください。
1.4. プロアクティブ認証
Quarkus では、プロアクティブ認証がデフォルトで有効になっています。受信リクエストに認証情報がある場合、ターゲットページで認証が不要な場合でもリクエストは常に認証されます。詳細は、Quarkus の プロアクティブ認証 ガイドを参照してください。
1.5. Quarkus Security のカスタマイズ
Quarkus Security はカスタマイズできます。Quarkus の次のコアセキュリティーコンポーネントをカスタマイズできます。
-
HttpAuthenticationMechanism
-
IdentityProvider
-
SecurityidentityAugmentor
リアクティブセキュリティーやセキュリティープロバイダーの登録方法など、Quarkus Security のカスタマイズの詳細は、Quarkus の Security tips and tricks ガイドを参照してください。
1.6. 参考資料
第2章 Quarkus の認証メカニズム
Quarkus Security フレームワークは、アプリケーションの保護に使用できる複数の認証メカニズムをサポートしています。認証メカニズムを組み合わせることもできます。
Quarkus アプリケーションの保護に使用する認証メカニズムを選択する前に、提供されている情報を確認してください。
2.1. サポート対象の認証メカニズムの概要
サポートされている認証メカニズムの一部は Quarkus に組み込まれていますが、エクステンションの追加が必要なものもあります。これらすべてのメカニズムについては、次のセクションで詳しく説明します。
次の表は、Quarkus で使用できるサポート対象メカニズムと特定の認証要件をマッピングしています。
認証要件 | 認証メカニズム |
---|---|
ユーザー名およびパスワード | |
ベアラーアクセストークン | |
シングルサインオン (SSO) | |
クライアント証明書 |
詳細は、次の トークン認証メカニズムの比較 表を参照してください。
2.2. ビルトイン認証メカニズム
Quarkus Security は、次のビルトイン認証サポートを提供します。
2.2.1. Basic 認証
ビルトイン HTTP Basic 認証メカニズムを使用して、Quarkus アプリケーションのエンドポイントを保護できます。詳細は、以下のドキュメントを参照してください。
2.2.2. フォームベース認証
Quarkus は、従来の Servlet フォームベース認証と同様に機能するフォームベース認証を提供します。従来のフォーム認証とは異なり、Quarkus はクラスター化された HTTP セッションをサポートしていないため、認証されたユーザーは HTTP セッションに保存されません。代わりに、認証情報が暗号化された Cookie に保存されます。同じ暗号鍵を共有するすべてのクラスターメンバーは、これを読み取ることができます。
暗号化を適用するには、quarkus.http.auth.session.encryption-key
プロパティーを追加し、設定する値が 16 文字以上であることを確認します。暗号鍵は、SHA-256 を使用してハッシュされます。結果のダイジェストは、Cookie 値の AES-256 暗号化の鍵として使用されます。Cookie には暗号化された値の一部として有効期限が含まれているため、クラスター内のすべてのノードのクロックを同期する必要があります。セッションが使用中の場合、更新された有効期限を持つ新しい Cookie が 1 分ごとに生成されます。
フォーム認証の使用を開始するには、Basic 認証の有効化 で説明されている設定と同様の設定が必要であり、quarkus.http.auth.form.enabled
を true
に設定する必要があります。
フォームベース認証を使用した単純な application.properties
は次のようになります。
quarkus.http.auth.form.enabled=true quarkus.http.auth.form.login-page=login.html quarkus.http.auth.form.landing-page=hello quarkus.http.auth.form.error-page= # Define testing user quarkus.security.users.embedded.enabled=true quarkus.security.users.embedded.plain-text=true quarkus.security.users.embedded.users.alice=alice quarkus.security.users.embedded.roles.alice=user
application.properties ファイルでユーザー名、シークレット、およびロールを設定するのは、テストシナリオに限定されます。実稼働環境のアプリケーションを保護するには、データベースまたは LDAP を使用してこの情報を保存する必要があります。詳細は、Jakarta Persistence を使用した Quarkus Security または Basic 認証を有効化 に記載されているその他の情報を参照してください。
アプリケーションのログインページには、以下と同様の HTML フォームが含まれます。
<form action="/j_security_check" method="post"> <label>Username</label> <input type="text" placeholder="Username" name="j_username" required> <label>Password</label> <input type="password" placeholder="Password" name="j_password" required> <button type="submit">Login</button> </form>
シングルページアプリケーション (SPA) では、通常、次の例に示すように、デフォルトのページパスを削除してリダイレクトを回避する必要があります。
# do not redirect, respond with HTTP 200 OK quarkus.http.auth.form.landing-page= # do not redirect, respond with HTTP 401 Unauthorized quarkus.http.auth.form.login-page= quarkus.http.auth.form.error-page= # HttpOnly must be false if you want to log out on the client; it can be true if logging out from the server quarkus.http.auth.form.http-only-cookie=false
SPA のリダイレクトを無効にしたため、クライアントからプログラムによってログインおよびログアウトする必要があります。以下は、j_security_check
エンドポイントにログインし、Cookie を破棄することでアプリケーションからログアウトする JavaScript メソッドの例です。
const login = () => { // Create an object to represent the form data const formData = new URLSearchParams(); formData.append("j_username", username); formData.append("j_password", password); // Make an HTTP POST request using fetch against j_security_check endpoint fetch("j_security_check", { method: "POST", body: formData, headers: { "Content-Type": "application/x-www-form-urlencoded", }, }) .then((response) => { if (response.status === 200) { // Authentication was successful console.log("Authentication successful"); } else { // Authentication failed console.error("Invalid credentials"); } }) .catch((error) => { console.error(error); }); };
クライアントから SPA をログアウトするには、Cookie を quarkus.http.auth.form.http-only-cookie=false
に設定して、Cookie を破棄し、可能であればメインページにリダイレクトできるようにする必要があります。
const logout= () => { // delete the credential cookie, essentially killing the session const removeCookie = `quarkus-credential=; Max-Age=0;path=/`; document.cookie = removeCookie; // perform post-logout actions here, such as redirecting back to your login page };
サーバーから SPA をログアウトするには、Cookie を quarkus.http.auth.form.http-only-cookie=true
に設定し、このサンプルコードを使用して Cookie を破棄します。
import io.quarkus.security.identity.CurrentIdentityAssociation;
import io.quarkus.vertx.http.runtime.security.FormAuthenticationMechanism;
import jakarta.ws.rs.core.Response;
import jakarta.ws.rs.POST;
@Inject
CurrentIdentityAssociation identity;
@POST
public Response logout() {
if (identity.getIdentity().isAnonymous()) {
throw new UnauthorizedException("Not authenticated");
}
FormAuthenticationMechanism.logout(identity.getIdentity()); 1
return Response.noContent().build();
}
- 1
- セッション Cookie を削除してログアウトを実行します。
フォームベース認証を設定するには、次のプロパティーを使用できます。
ビルド時に固定された設定プロパティー: その他の設定プロパティーはすべて実行時にオーバーライドできます。
設定プロパティー | 型 | Default |
権限セット全体を有効にするかどうかを決定します。 デフォルトでは、権限セットが定義されている場合は有効になります。
環境変数: | boolean | |
この権限セットがリンクされている HTTP ポリシー。 ビルトインポリシーには、permit、deny、authenticated の 3 つがあります。ロールベースのポリシーを定義でき、エクステンションは独自のポリシーを追加できます。
環境変数: | string |
required
|
この権限セットが適用されるメソッド。これが設定されていない場合は、すべてのメソッドに適用されます。 リクエストが任意の権限セットからの任意のパスに一致し、そのメソッドがリストされていないために制約に一致しない場合、リクエストは拒否されることに注意してください。 メソッド固有の権限は、メソッドが設定されていない一致よりも優先されます。 たとえば、Quarkus が /admin への GET および POST リクエストを許可するように設定されていて、他の権限が設定されていない場合、/admin への PUT リクエストは拒否されます。
環境変数: | list of string | |
この権限チェックが適用されるパス。パスが /* で終わる場合はパスの接頭辞として処理され、それ以外の場合は完全一致として処理されます。 一致は長さに基づいて行われるため、パスに最も具体的に一致する場合が優先されます。 複数の権限セットが同じパスに一致する場合、メソッドの明示的な一致がメソッドが設定されていない一致よりも優先され、それ以外の場合は最も制限の厳しい権限が適用されます。
環境変数: | list of string | |
ユーザー認証に使用しなければならないパス固有の認証メカニズム。'basic'、'bearer'、'form' などの
環境変数: | string | |
このポリシーが、優先されるパスのポリシーに加え、一致したパスにも必ず適用されることを示しています。パフォーマンスへの影響を最小限に抑えるため、複数の共有ポリシーは作成しないでください。
環境変数: | boolean |
|
権限チェックをすべての一致するパスに適用するか、Jakarta REST リソースのパスにのみ適用するかを指定します。
環境変数: | all: すべての一致するパスに適用します。
jaxrs: 権限チェックを Jakarta REST リクエストパスにのみ適用する必要があることを宣言します。このオプションを使用すると、一致する Jakarta REST エンドポイントでアノテーションを使用して認証メカニズムを選択した場合の権限チェックを遅延できます。次の REST エンドポイントアノテーションを使用する場合は、このオプションを設定する必要があります。テナント識別子を持つ OIDC 認証メカニズムを選択する | all |
このポリシーによって保護されているリソースへのアクセスが許可されるロール。デフォルトでは、すべての認証済みユーザーにアクセスが許可されます。
環境変数: | list of string |
|
環境変数: | Map<String,List<String>> | |
このポリシーが正常に適用され (ポリシーによりリクエストの続行が許可される)、認証されたリクエストに必要なロールがある場合に、
環境変数: | Map<String,List<String>> | |
このポリシーによって付与される権限は、この設定プロパティーによって指定された
環境変数: | string |
|
たとえば、
環境変数: | Map<String,List<String>> | |
証明書プロパティーファイルで指定されたロールマッピングに従って、値が 'SecurityIdentity' ロールにマッピングされるクライアント証明書属性。属性は、相対識別名 (RDN) またはサブジェクト代替名 (SAN) のいずれかである必要があります。デフォルトでは、コモンネーム (CN) 属性値がロールマッピングに使用されます。対応している値は次のとおりです。
環境変数: | string |
|
ロールマッピングへのクライアント証明書の属性値が含まれるプロパティーファイル。
プロパティーファイルは
環境変数: | path | |
認証レルム
環境変数: | string | |
ログインページ。
環境変数: | string |
|
ユーザー名のフィールド名。
環境変数: | string |
|
パスワードのフィールド名。
環境変数: | string |
|
エラーページ。
環境変数: | string |
|
リダイレクト先の保存済みページがない場合にリダイレクトするランディングページ。
環境変数: | string |
|
アクセスしたい場所にユーザーをリダイレクトするために使用される Cookie の名前を制御するオプション。
環境変数: | string |
|
非アクティブ (アイドル) タイムアウト 非アクティブタイムアウトに達すると、Cookie が更新されず、新しいログインが強制されます。
環境変数: |
| |
Cookie が、タイムアウトが更新された新しい Cookie に置き換えられるまでの Cookie 存続期間 ("renewal-timeout" とも呼ばれます)。 値が小さいほど、サーバーの負荷がわずかに増加します (新しい暗号化された Cookie がより頻繁に生成されるため)。ただし、値が大きいと、Cookie の生成時にタイムアウトが設定されるため、非アクティブタイムアウトに影響します。 たとえばこれが 10 分に設定され、非アクティブタイムアウトが 30 分に設定された場合、ユーザーの最終リクエストの Cookie 経過時間が 9 分と仮定すると、タイムアウトは新しい Cookie が生成された後でなければ更新されないため、実際のタイムアウトは最終リクエストの 21 分後に発生します。 つまり、サーバー側ではタイムアウトは追跡されず、タイムスタンプは Cookie 自体にエンコードおよび暗号化され、リクエストごとに復号化されて解析されます。
環境変数: |
| |
永続的なセッションの保存に使用される Cookie。
環境変数: | string |
|
セッションクッキーとロケーション Cookie の Cookie パス。
環境変数: | string |
|
JavaScript 経由での Cookie へのアクセスを防ぐために、HttpOnly 属性を設定します。
環境変数: | boolean |
|
セッションおよびロケーションクッキーの SameSite 属性。
環境変数: |
|
|
セッション Cookie の Max-Age 属性。これはブラウザーが Cookie を保持する時間の長さです。 デフォルト値は空です。つまり、ブラウザーが閉じられるまで Cookie が保持されます。
環境変数: | ||
登録されているすべての HTTP 認証メカニズムがリクエストの認証情報の検証を試行することを必須とします。
デフォルトでは、 生成されたすべてのセキュリティーアイデンティティーは、次のユーティリティーメソッドを使用して取得できます。 `io.quarkus.vertx.http.runtime.security.HttpSecurityUtils++#++getSecurityIdentities(io.quarkus.security.identity.SecurityIdentity)`
注入された
このプロパティーは、デフォルトでは false に設定されます。この設定の場合、最初の パス固有の認証が有効になっている場合、このプロパティーは無視されます。
環境変数: | boolean |
|
統合認証モード。
環境変数: | lax: 登録されている HTTP 認証メカニズムの少なくとも 1 つがアイデンティティーを作成すると、認証が成功します。
strict: 登録されているすべての HTTP 認証メカニズムがアイデンティティーを作成すると、認証が成功します。通常、認証情報が mTLS 経由で伝送され、mTLS と別の認証 (OIDC ベアラートークン認証など) の両方が成功する必要がある場合、統合認証を strict モードにする必要があります。この場合、最初のメカニズムである mTLS によって作成された | strict |
duration の値を書き込むには、標準の java.time.Duration
フォーマットを使用します。詳細は、Duration#parse() Java API ドキュメント を参照してください。
数字で始まる簡略化されたフォーマットも使用できます。
- 値が数値のみの場合は、秒単位の時間を表します。
-
数字の後に
ms
が続く値は、ミリ秒単位の時間を表します。
その他の場合は、解析のために簡略化されたフォーマットが java.time.Duration
フォーマットに変換されます。
-
数字の後に
h
、m
、またはs
が続く値には、接頭辞PT
が付きます。 -
数字の後に
d
が続く値は、接頭辞P
が付きます。
2.2.3. 相互 TLS 認証
Quarkus は相互 TLS (mTLS) 認証を提供するため、X.509 証明書に基づきユーザーを認証できます。
この認証方法を使用するには、まずアプリケーションで SSL/TLS を有効にする必要があります。詳細は、Quarkus の「HTTP reference」ガイドの Supporting secure connections with SSL/TLS セクションを参照してください。
アプリケーションがセキュアな接続を受け入れた後、アプリケーションが信頼するすべての証明書を保持するファイルの名前を使用して quarkus.http.ssl.certificate.trust-store-file
プロパティーを設定します。このファイルには、ブラウザーや他のサービスなどのクライアントが保護されたリソースの 1 つにアクセスしようとしたときに、アプリケーションが証明書を要求する方法に関する情報も含まれています。
JKS は Quarkus のデフォルトのキーストアおよびトラストストア形式ではなくなったため、Quarkus のフレームワークはファイル拡張子に基づいて推測を行います。
-
.pem
、.crt
、.key
は PEM 証明書および鍵として読み取られます。 -
.jks
、.keystore
、.truststore
ファイルは JKS キーストアおよびトラストストアとして読み取られます。 -
.p12
、.pkcs12
、.pfx
ファイルは PKCS12 キーストアおよびトラストストアとして読み取られます。
ファイルでこれらの拡張子が使用されていない場合は、次のプロパティーを使用して形式を設定する必要があります。
quarkus.http.ssl.certificate.key-store-file-type=JKS # or P12 or PEM quarkus.http.ssl.certificate.trust-store-file-type=JKS # or P12 or PEM
JKS はあまり使用されなくなってきています。Java 9 以降、Java のデフォルトのキーストア形式は PKCS12 です。JKS と PKCS12 の最も大きな違いは、JKS が Java 固有の形式であることです。対照的に、PKCS12 は、暗号化された秘密鍵と証明書を保存するための、言語に依存しない標準化された方式です。
mTLS を有効にするための設定例を次に示します。
quarkus.http.ssl.certificate.key-store-file=server-keystore.jks 1 quarkus.http.ssl.certificate.key-store-password=the_key_store_secret quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks 2 quarkus.http.ssl.certificate.trust-store-password=the_trust_store_secret quarkus.http.ssl.client-auth=required 3 quarkus.http.auth.permission.default.paths=/* 4 quarkus.http.auth.permission.default.policy=authenticated quarkus.http.insecure-requests=disabled 5
- 1
- サーバーの秘密鍵が保存されているキーストア。
- 2
- 信頼済み証明書がロードされるトラストストア。
- 3
quarkus.http.ssl.client-auth
をrequired
に設定すると、サーバーがクライアント証明書を要求します。サーバーが証明書なしでリクエストを受け入れる必要がある場合は、REQUEST
に設定できます。この設定は、mTLS 以外の複数の認証方法をサポートする場合に便利です。- 4
- 認証されたユーザーのみがアプリケーションのリソースにアクセスできるようにするポリシーを定義します。
- 5
- プレーン HTTP プロトコルを無効にし、すべてのリクエストで HTTPS を使用するように要求します。
quarkus.http.ssl.client-auth
をrequired
に設定すると、quarkus.http.insecure-requests
が自動的に無効になります。
受信リクエストがトラストストア内の有効な証明書と一致する場合、アプリケーションは次のように SecurityIdentity
を注入してサブジェクトを取得できます。
サブジェクトの取得
@Inject SecurityIdentity identity; @GET @Produces(MediaType.TEXT_PLAIN) public String hello() { return String.format("Hello, %s", identity.getPrincipal().getName()); }
次の例に示すコードを使用して証明書を取得することもできます。
証明書の取得
import java.security.cert.X509Certificate; import io.quarkus.security.credential.CertificateCredential; CertificateCredential credential = identity.getCredential(CertificateCredential.class); X509Certificate certificate = credential.getCertificate();
2.2.3.1. 証明書属性をロールにマッピングする
クライアント証明書の情報を使用して、Quarkus SecurityIdentity
にロールを追加できます。
クライアント証明書のコモンネーム (CN) 属性を確認した後、SecurityIdentity
に新しいロールを追加できます。新しいロールを追加する最も簡単な方法は、証明書属性をロールマッピング機能に使用する方法です。
たとえば、相互 TLS 認証 を紹介するセクションに示されるプロパティーを次のように更新できます。
quarkus.http.ssl.certificate.key-store-file=server-keystore.jks quarkus.http.ssl.certificate.key-store-password=the_key_store_secret quarkus.http.ssl.certificate.trust-store-file=server-truststore.jks quarkus.http.ssl.certificate.trust-store-password=the_trust_store_secret quarkus.http.ssl.client-auth=required quarkus.http.insecure-requests=disabled quarkus.http.auth.certificate-role-properties=cert-role-mappings.properties 1 quarkus.http.auth.permission.certauthenticated.paths=/* 2 quarkus.http.auth.permission.certauthenticated.policy=role-policy-cert 3 quarkus.http.auth.policy.role-policy-cert.roles-allowed=user,admin 4
上記の設定では、クライアント証明書の CN 属性が alice
または bob
の場合にリクエストが認可され、jdoe
の場合はリクエストが拒否されます。
2.2.3.2. 証明書属性を使用して SecurityIdentity を強化する
自動で 証明書属性をロールにマッピングする オプションが適していない場合は、いつでも SecurityIdentityAugmentor
を登録できます。カスタム SecurityIdentityAugmentor
を使用して、さまざまなクライアント証明書属性の値を確認し、それに応じて SecurityIdentity
を拡張できます。
SecurityIdentity
のカスタマイズの詳細は、Quarkus の「Security tips and tricks」ガイドの Security identity customization セクションを参照してください。
2.3. サポート対象のその他の認証メカニズム
Quarkus Security はエクステンションを使用して次の認証メカニズムもサポートします。
2.3.1. OpenID Connect 認証
OpenID Connect (OIDC) は、OAuth 2.0 プロトコル上で動作するアイデンティティーレイヤーです。OIDC を使用すると、クライアントアプリケーションは、OIDC プロバイダーによって実行される認証に基づきユーザーのアイデンティティーを確認し、そのユーザーに関する基本情報を取得できます。
Quarkus の quarkus-oidc
エクステンションは、ベアラートークンと認可コードフローの認証メカニズムをサポートする、リアクティブで相互運用可能なマルチテナント対応の OIDC アダプターを提供します。ベアラートークン認証メカニズムは、HTTP 認証ヘッダーからトークンを展開します。
認可コードフローメカニズムは、ユーザーを OIDC プロバイダーにリダイレクトして、ユーザーのアイデンティティーを認証します。ユーザーが Quarkus にリダイレクトされた後、メカニズムにより ID、アクセストークン、およびリフレッシュトークンに付与された提供コードを交換して認証プロセスを完了します。
更新可能な JSON Web Key (JWK) セットを使用して ID の検証と JSON Web Token (JWT) トークンへのアクセスを行うか、リモートでそれらをイントロスペクトできます。ただし、バイナリートークンとも呼ばれる不透明トークンは、リモートでのみイントロスペクトできます。
Quarkus OIDC エクステンションを使用すると、ベアラートークンと認可コードフロー認証メカニズムは SmallRye JWT 認証 を使用して、JWT トークンを MicroProfile JWT org.eclipse.microprofile.jwt.JsonWebToken
として表します。
2.3.1.1. OIDC 認証に使用する追加の Quarkus リソース
Quarkus アプリケーションの保護に使用できる OIDC 認証および認可方法の詳細は、次のリソースを参照してください。
OIDC トピック | Quarkus 情報リソース |
---|---|
ベアラートークン認証メカニズム | |
認可コードフロー認証メカニズム | |
OIDC と SAML アイデンティティーブローカー | |
ベアラートークン認証または認可コードフローメカニズムをサポートできるマルチテナント | |
一般的に使用される OpenID Connect プロバイダーを使用して Quarkus を保護する | |
Keycloak を使用して認証を一元化する |
実行時に Quarkus OIDC エクステンションを有効にするには、ビルド時に quarkus.oidc.tenant-enabled=false
を設定します。次に、システムプロパティーを使用して実行時に再度有効にします。
マルチテナント OIDC デプロイメントにおける個々のテナント設定の管理に関する詳細は、「OpenID Connect (OIDC) マルチテナンシーの使用」ガイドの テナント設定を無効にする セクションを参照してください。
2.3.1.2. OpenID Connect クライアントとフィルター
quarkus-oidc-client
エクステンションは、次のトークングラントをサポートする OpenID Connect および OAuth2 プロバイダーからアクセストークンを取得し、更新するための OidcClient
を提供します。
-
client-credentials
-
password
-
refresh_token
quarkus-resteasy-client-oidc-filter
エクステンションには、quarkus-oidc-client
エクステンションが必要です。これは、OidcClient
によって取得されたアクセストークンを HTTP Authorization
ヘッダーの Bearer
スキーム値として設定する JAX-RS RESTful Web サービス OidcClientRequestFilter
を提供します。このフィルターは、現在の Quarkus エンドポイントに注入された MicroProfile REST クライアント実装に登録できますが、このサービスエンドポイントの認証要件とは関係ありません。たとえば、パブリックエンドポイントにしたり、mTLS で保護したりできます。
このシナリオでは、Quarkus OpenID Connect アダプターを使用して Quarkus エンドポイントを保護する必要はありません。
quarkus-resteasy-client-oidc-token-propagation
エクステンションには、quarkus-oidc
エクステンションが必要です。これは、OpenID Connect ベアラートークンまたは認可コードフローアクセストークンを HTTP Authorization
ヘッダーの Bearer
スキーム値として設定する Jakarta REST TokenCredentialRequestFilter
を提供します。このフィルターは、現在の Quarkus エンドポイントに注入された MicroProfile REST クライアント実装に登録できます。これは、Quarkus OIDC アダプターを使用して保護する必要があります。このフィルターは、アクセストークンをダウンストリームサービスに伝播できます。
詳細は、OpenID Connect クライアントとトークンの伝播のクイックスタート と、OpenID Connect (OIDC) および OAuth2 クライアントとフィルターのリファレンス ガイドを参照してください。
2.3.2. SmallRye JWT 認証
quarkus-smallrye-jwt
エクステンションは、MicroProfile JSON Web Token (JWT) 2.1 実装と、署名および暗号化された JWT
トークンを検証するための複数のオプションを提供します。これらは org.eclipse.microprofile.jwt.JsonWebToken
として表されます。
quarkus-smallrye-jwt
は、quarkus-oidc
ベアラートークン認証メカニズムの代替手段であり、Privacy Enhanced Mail (PEM) キーまたは更新可能な JWK
キーセットのいずれかを使用して JWT
トークンのみを検証します。quarkus-smallrye-jwt
は JWT 生成 API も提供しており、これを使用することで signed
、inner-signed
、encrypted
の JWT
トークンを簡単に作成できます。
詳細は、JWT RBAC の使用 ガイドを参照してください。
2.4. OpenID Connect および SmallRye JWT 認証メカニズムの選択
次の情報を参考にして、Quarkus アプリケーションを保護するための適切なトークン認証メカニズムを選択します。
認証メカニズムのユースケースリスト
-
quarkus-oidc
には、ベアラートークンの検証と、認可コードフローでのエンドユーザーの認証が可能な Keycloak などの OpenID Connect プロバイダーが必要です。いずれの場合も、quarkus-oidc
には指定された OpenID Connect プロバイダーへの接続が必要です。 -
ユーザー認証に認可コードフローが必要な場合、または複数のテナントをサポートする必要がある場合は、
quarkus-oidc
を使用します。quarkus-oidc
は、認可コードフローとベアラーアクセストークンの両方を使用してユーザー情報を要求することもできます。 -
ベアラートークンを検証する必要がある場合は、
quarkus-oidc
またはquarkus-smallrye-jwt
を使用します。 -
ベアラートークンが JSON Web トークン (JWT) 形式の場合は、前述のリストから任意のエクステンションを使用できます。
quarkus-oidc
とquarkus-smallrye-jwt
はどちらも、OpenID Connect プロバイダーがキーをローテーションするときにJsonWebKey
(JWK) セットの更新をサポートします。したがって、リモートトークンのイントロスペクションを回避する必要がある、またはそれがプロバイダーによってサポートされていない場合は、quarkus-oidc
またはquarkus-smallrye-jwt
を使用して JWT トークンを検証します。 -
JWT トークンをリモートでイントロスペクトするには、リモートイントロスペクションを使用することで、不透明トークンまたはバイナリートークンの検証に
quarkus-oidc
を使用できます。quarkus-smallrye-jwt
は、不透明トークンと JWT トークンの両方のリモートイントロスペクションをサポートしていません。代わりに、通常は OpenID Connect プロバイダーから取得されるローカルで利用可能なキーに依存しています。 -
quarkus-oidc
とquarkus-smallrye-jwt
は、エンドポイントコードへの JWT と不透明トークンの注入をサポートします。注入された JWT トークンは、ユーザーに関する詳細情報を提供します。すべてのエクステンションには、Principal
として注入されたトークンを含めることができます。 -
quarkus-smallrye-jwt
は、quarkus-oidc
よりも多くのキー形式をサポートしています。quarkus-oidc
は、JWK セットの一部である JWK 形式のキーのみを使用しますが、quarkus-smallrye-jwt
は PEM キーをサポートします。 -
quarkus-smallrye-jwt
は、ローカルで署名されたトークン、内部で署名および暗号化されたトークン、および暗号化されたトークンを処理します。一方で、quarkus-oidc
もこれらのトークンを検証できますが、不透明トークンとして扱い、リモートイントロスペクションを通じて検証します。
アーキテクチャーを考慮して、不透明トークン形式または JSON Web トークン (JWT) 形式のどちらを使用するかが決定されます。不透明トークンは JWT トークンよりもはるかに短くなる傾向がありますが、トークンに関連付けられた状態のほとんどをプロバイダーデータベースで維持する必要があります。実質的に、不透明トークンはデータベースポインターです。
JWT トークンは不透明トークンよりも大幅に長くなります。その場合もプロバイダーは、トークンクレームとしてトークン関連の状態を保存し、それに署名するか暗号化することで、トークン関連の状態の大部分をクライアントに委譲します。
必要な機能 | 認証メカニズム | |
---|---|---|
|
| |
ベアラー JWT 検証 | ローカル検証またはイントロスペクション | ローカル検証 |
ベアラー不透明トークン検証 | イントロスペクション | なし |
JWT トークン検証用に | はい | はい |
トークンを | はい | はい |
JWT を MP JWT として注入する | はい | はい |
認可コードフロー | はい | なし |
マルチテナンシー | はい | なし |
ユーザー情報のサポート | はい | なし |
PEM キー形式のサポート | なし | はい |
SecretKey のサポート | なし | JSON Web Key (JWK) 形式 |
内部署名および暗号化されたトークン、または暗号化されたトークン | イントロスペクション | ローカル検証 |
カスタムトークン検証 | なし | 注入された JWT パーサーを使用 |
Cookie としての JWT をサポートする | なし | はい |
2.5. 認証メカニズムの組み合わせ
異なるソースからユーザー認証情報が提供される場合は、認証メカニズムを組み合わせることができます。たとえば、組み込みの Basic 認証メカニズムと Quarkus quarkus-oidc
ベアラートークン認証メカニズムを組み合わせることができます。
いずれかの認証メカニズムによって最初の SecurityIdentity
が生成されると、すぐに認証プロセスが完了します。
2.5.1. 統合認証
場合によっては、登録されているすべての認証メカニズムが SecurityIdentity
を作成することが必要になることがあります。これが必要になるのは、トークンなどの認証情報を 相互 TLS 認証 経由で渡す必要がある場合です。たとえば、ユーザーが Virtual Private Network
経由で認証している場合や、トークンの検証を成功させるために現在のトークンをクライアント証明書にバインドして、このトークンをクライアント証明書とともに Quarkus に渡している同じクライアントにトークンが正確に発行されたことを保証する場合などです。
Quarkus ではこのような認証は inclusive
(統合認証) と呼ばれ、次のようにして有効にできます。
quarkus.http.auth.inclusive=true
認証が統合認証である場合、最初の認証メカニズムによって作成された SecurityIdentity
をアプリケーションコードに注入できます。たとえば、相互 TLS 認証 と Basic 認証メカニズムの両方の認証が必要な場合、相互 TLS 認証 メカニズムが最初に SecurityIdentity
を作成します。
追加の SecurityIdentity
インスタンスには、最初の SecurityIdentity
の quarkus.security.identities
属性としてアクセスできます。しかし、これらの追加のアイデンティティーに直接アクセスする必要がない場合があります。たとえば、相互 TLS 認証 メカニズムと OIDC ベアラー認証 メカニズムの両方が組み合わされて認証が行われている場合、認証されたベアラートークンは、相互 TLS 認証 によって作成された SecurityIdentity
とともにトークン認証情報として注入できます。以下に例を示します。
package org.acme.security; import io.quarkus.oidc.AccessTokenCredential; import io.quarkus.oidc.common.runtime.OidcConstants; import io.quarkus.security.identity.SecurityIdentity; import io.quarkus.vertx.http.runtime.security.HttpSecurityUtils; import jakarta.enterprise.context.ApplicationScoped; import jakarta.inject.Inject; @ApplicationScoped public class InclusiveAuthExampleBean { @Inject SecurityIdentity mtlsIdentity; 1 @Inject AccessTokenCredential accessTokenCredential; private AccessTokenCredential getAccessTokenCredential() { if (doItHardWay()) { var securityIdentities = HttpSecurityUtils.getSecurityIdentities(mtlsIdentity); 2 if (securityIdentities != null) { SecurityIdentity bearerIdentity = securityIdentities.get(OidcConstants.BEARER_SCHEME); if (bearerIdentity != null) { return bearerIdentity.getCredential(AccessTokenCredential.class); } } } return accessTokenCredential; } }
Quarkus quarkus-oidc
ベアラートークンと smallrye-jwt
認証メカニズムは、両方とも HTTP ベアラートークン認証スキームから抽出されたトークンを検証しようとするため、この 2 つを組み合わせることはできません。
2.5.2. パスベース認証
2.5.2.1. HTTP セキュリティーポリシーを使用してパスベース認証を有効にする
次の設定例は、特定のリクエストパスに対して 1 つの認証メカニズムのみ選択できるようにする方法を示しています。
quarkus.http.auth.permission.basic-or-bearer.paths=/service quarkus.http.auth.permission.basic-or-bearer.policy=authenticated quarkus.http.auth.permission.basic.paths=/basic-only quarkus.http.auth.permission.basic.policy=authenticated quarkus.http.auth.permission.basic.auth-mechanism=basic quarkus.http.auth.permission.bearer.paths=/bearer-only quarkus.http.auth.permission.bearer.policy=authenticated quarkus.http.auth.permission.bearer.auth-mechanism=bearer
auth-mechanism
プロパティーの値が、HttpAuthenticationMechanism
でサポートされている認証スキーム (basic
、bearer
、form
など) と一致していることを確認します。
2.5.2.2. アノテーションを使用して Jakarta REST エンドポイントのパスベース認証を有効にする
アノテーションを使用して、各 Jakarta REST エンドポイントに固有の認証メカニズムを選択できます。アノテーションを使用して認証メカニズムを選択できるのは、REST エンドポイントが一致した後に限定されるため、この機能は プロアクティブ認証 が無効になっている場合にのみ有効になります。以下の方法で、REST エンドポイントごとに認証メカニズムを選択できます。
quarkus.http.auth.proactive=false
import io.quarkus.oidc.AuthorizationCodeFlow; import io.quarkus.vertx.http.runtime.security.annotation.BasicAuthentication; import jakarta.annotation.security.RolesAllowed; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; @Path("hello") public class HelloResource { @GET @BasicAuthentication 1 2 @Path("basic") public String basicAuthMechanism() { return "basic"; } @GET @RolesAllowed("admin") 3 @AuthorizationCodeFlow 4 @Path("code-flow") public String codeFlowAuthMechanism() { return "code-flow"; } }
- 1
- REST エンドポイント
/hello/basic
には、Basic 認証 を使用しなければアクセスできません。 - 2
@BasicAuthentication
アノテーションに標準のセキュリティーアノテーションが付属していない場合は、デフォルトで@Authenticated
アノテーションが追加されるため、このエンドポイントには認証が必要です。- 3
@AuthorizationCodeFlow
アノテーションは、@RolesAllowed
や@PermissionsAllowed
などの他の標準セキュリティーアノテーションと組み合わせることができます。- 4
- REST エンドポイント
/hello/code-flow
には、OIDC 認可コードフローメカニズム を使用しなければアクセスできません。
認証メカニズム | アノテーション |
---|---|
Basic 認証メカニズム |
|
フォームベース認証メカニズム |
|
相互 TLS 認証メカニズム |
|
ベアラートークン認証メカニズム |
|
OIDC 認可コードフローメカニズム |
|
SmallRye JWT 認証メカニズム |
|
Quarkus は、認証メカニズムアノテーションが付けられたエンドポイントを自動的に保護します。REST エンドポイントとリソースに標準のセキュリティーアノテーションが存在しない場合は、io.quarkus.security.Authenticated
アノテーションが追加されます。
io.quarkus.vertx.http.runtime.security.annotation.HttpAuthenticationMechanism
アノテーションを使用して、スキームに基づき任意の認証メカニズムを選択することもできます。アノテーションベースでは、quarkus.http.auth.permission.basic.auth-mechanism=custom
設定プロパティーは @HttpAuthenticationMechanism("custom")
アノテーションに相当します。
さまざまな Jakarta EE 仕様との整合性を保つために、アノテーションの継承に依存するのではなく、常にアノテーションを繰り返すことが推奨されます。
2.5.2.3. 統合認証を使用したパスベース認証の有効化
デフォルトでは、Quarkus は パスベース認証 において、1 つのパスにつき 1 つの認証メカニズムしかサポートしていません。パスベース認証に複数の認証メカニズムを使用する必要がある場合は、「Security Tips and Tricks」ガイドの Dealing with more than one HttpAuthenticationMechanism セクションに記載されているように、カスタムの HttpAuthenticationMechanism
を作成できます。もう 1 つの方法は、統合認証 を lax モードで有効にして、登録されているすべての HTTP 認証メカニズムがメカニズム固有の SecurityIdentity
を作成したことを確認するカスタムの HttpSecurityPolicy
または PermissionChecker
を記述することです。
lax モードでの統合認証の有効化
quarkus.http.auth.inclusive-mode=lax 1
quarkus.http.auth.inclusive=true
- 1
- 統合認証では、デフォルトで、登録されているすべての HTTP 認証メカニズムが
SecurityIdentity
を作成する必要があります。一方、lax モードでは、少なくとも 1 つ以上の登録済みのHttpAuthenticationMechanism
がSecurityIdentity
を作成すると、認証が成功します。
たとえば、mTLS、Basic、OIDC の 3 つの登録済みメカニズムがあり、hello
メソッドへのアクセスを許可するのに必要なものが、Basic 認証と mTLS 認証の成功だけであるとします。この場合、lax モードで統合認証を有効にすると、次の例に示すように、アイデンティティーを生成したメカニズムを確認できます。
HTTP 認証メカニズムのチェックの例
import io.quarkus.security.PermissionChecker;
import io.quarkus.security.PermissionsAllowed;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.vertx.http.runtime.security.HttpSecurityUtils;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import java.util.Map;
@Path("/hello")
public class HelloResource {
@PermissionsAllowed("mtls-basic")
@GET
public String hello() {
return "Hello world";
}
@PermissionChecker("mtls-basic")
boolean isMtlsAndBasicAuthentication(SecurityIdentity identity) {
Map<String, SecurityIdentity> identities = HttpSecurityUtils.getSecurityIdentities(identity);
if (identities != null) {
return identities.containsKey("basic") && identities.containsKey("x509"); 1
}
return false;
}
}
- 1
mTLS
とBasic
の両方の認証メカニズムが現在のリクエストを認証したことが確認された場合にのみ、エンドポイントへのアクセスを許可します。
2.5.2.4. HTTP セキュリティーポリシーとの組み合わせ方法
個々のリソースへのアクセスが許可されるロールを定義する最も簡単な方法は、@RolesAllowed
アノテーションを使用する方法です。ただし、次の例のように HTTP セキュリティーポリシーを使用することもできます。
quarkus.http.auth.policy.roles1.roles-allowed=user quarkus.http.auth.permission.roles1.paths=/hello/code-flow quarkus.http.auth.permission.roles1.applies-to=JAXRS 1 quarkus.http.auth.permission.roles1.policy=roles1 quarkus.http.auth.permission.roles1.methods=GET 2
2.6. プロアクティブ認証
Quarkus では、プロアクティブ認証がデフォルトで有効になっています。つまり、受信リクエストに認証情報がある場合、ターゲットページで認証が不要であっても、リクエストは必ず認証されます。詳細は、Quarkus の プロアクティブ認証 ガイドを参照してください。
2.7. 参考資料
第3章 アイデンティティープロバイダー
Quarkus Security フレームワークでは、アイデンティティープロバイダーはユーザーのアイデンティティーを検証することで、認証と認可における重要な役割を果たしています。IdentityProvider
は、SecurityIdentity
インスタンスを作成します。これは、ユーザー認証時に Quarkus アプリケーションへのアクセスリクエストを検証および認可するために使用されます。
IdentityProvider
は、HttpAuthenticationMechanism
によって提供される認証情報を SecurityIdentity
インスタンスに変換します。
OIDC や SmallRye JWT のエクステンションなど、一部のエクステンションには、サポートされている認証フローに固有のインライン IdentityProvider
の実装が含まれています。たとえば quarkus-oidc
は、独自の IdentityProvider
を使用してトークンを SecurityIdentity
インスタンスに変換します。
Basic 認証またはフォームベース認証を使用する場合は、ユーザー名とパスワードを SecurityIdentity
インスタンスに変換するために IdentityProvider
インスタンスを追加する必要があります。
Quarkus Security を開始する場合は、Quarkus のビルトイン Basic HTTP 認証と Jakarta Persistence アイデンティティープロバイダーを組み合わせて、ロールベースのアクセス制御 (RBAC) を有効にすることを検討してください。
Basic 認証とそのメカニズム、および関連するアイデンティティープロバイダーの詳細は、次の関連資料を参照してください。
第4章 プロアクティブ認証
設定のカスタマイズや例外の処理を含め、Quarkus でプロアクティブ認証を管理する方法を説明します。さまざまなアプリケーションシナリオにおける実用的な洞察とストラテジーを得ることができます。
Quarkus では、プロアクティブ認証がデフォルトで有効になっています。これにより、ターゲットページで認証が不要な場合でも、認証情報を持つすべての受信リクエストが必ず認証されます。その結果、ターゲットページが公開されている場合でも、無効な認証情報を持つリクエストは拒否されます。匿名のリクエストが許可されるため、認証情報のないリクエストは拒否されません。
ターゲットページで必要な場合にのみ認証を行う場合は、このデフォルトの動作をオフにできます。ターゲットページで要求される場合にのみ認証を行うためにプロアクティブ認証をオフにするには、application.properties
設定ファイルを次のように変更します。
quarkus.http.auth.proactive=false
プロアクティブ認証をオフにすると、アイデンティティーが要求された場合にのみ認証プロセスが実行されます。ユーザーの認証を必要とするセキュリティールールがある場合、または現在のアイデンティティーへのプログラムによるアクセスが必要な場合、アイデンティティーが要求される場合があります。
プロアクティブ認証が使用されていない場合、SecurityIdentity
へのアクセスはブロッキング操作になります。これは、認証がまだ行われておらず、SecurityIdentity
へのアクセスにはデータベースなどの外部システムへの呼び出しが必要になり、操作がブロックされる可能性があるためです。ブロッキングアプリケーションの場合、これは問題になりません。しかし、リアクティブアプリケーションで認証を無効にしている場合は、I/O スレッドでブロッキング操作を実行できないため、これは失敗します。この問題を回避するには、io.quarkus.security.identity.CurrentIdentityAssociation
のインスタンスに対して @Inject
を実行し、Uni<SecurityIdentity> getDeferredIdentity();
メソッドを呼び出す必要があります。次に、その結果として得られる Uni
をサブスクライブすると、認証が完了してアイデンティティーが利用可能になった場合に通知を受け取ることができます。
認証がすでに行われているため、@RolesAllowed
、@Authenticated
、またはそれぞれの設定の認可チェックでアノテーションが付けられたエンドポイントから、Quarkus REST (旧称 RESTEasy Reactive) の public SecurityIdentity getIdentity()
を使用して SecurityIdentity
に同期的にアクセスできます。ルートレスポンスが同期的である場合、これは Reactive ルート にも当てはまります。
プロアクティブ認証が無効な場合、void ではない保護されたメソッドが同期的に値を返すと、CDI Bean で使用される 標準のセキュリティーアノテーション が I/O スレッドで機能しません。この制限は、このようなメソッドが SecurityIdentity
にアクセスする必要があることから生じます。
次の例では、HelloResource
と HelloService
を定義します。/hello
へのすべての GET リクエストは I/O スレッドで実行され、BlockingOperationNotAllowedException
例外を出力します。
この例は、複数の方法で修正できます。
-
hello
エンドポイントにアノテーション@Blocking
を付け、ワーカースレッドに切り替えます。 -
リアクティブまたは非同期データ型を使用して、
sayHello
メソッドの戻り値の型を変更します。 -
@RolesAllowed
アノテーションをエンドポイントに移動します。エンドポイントメソッドからSecurityIdentity
にアクセスしてもブロッキング操作になることはないため、これは最も安全な方法の 1 つです。
import jakarta.annotation.security.PermitAll; import jakarta.inject.Inject; import jakarta.ws.rs.GET; import jakarta.ws.rs.Path; import io.smallrye.mutiny.Uni; @Path("/hello") @PermitAll public class HelloResource { @Inject HelloService helloService; @GET public Uni<String> hello() { return Uni.createFrom().item(helloService.sayHello()); } }
import jakarta.annotation.security.RolesAllowed; import jakarta.enterprise.context.ApplicationScoped; @ApplicationScoped public class HelloService { @RolesAllowed("admin") public String sayHello() { return "Hello"; } }
4.1. CDI リクエストコンテキストの有効化
場合によっては、認証および認可中に @RequestScoped
Bean を注入する必要があります。代表的な例としては、SecurityIdentity
のオーグメンテーション中にデータベースにアクセスすることが挙げられます。これは、「Security Tips and Tricks」ガイドの Security Identity Customization セクションで説明されています。jakarta.enterprise.context.ContextNotActiveException
で認証または認可が失敗した場合、プロアクティブ認証の無効化が最善の解決策となることがよくあります。また、ユーザーは @ActivateRequestContext
アノテーションなどを使用して CDI リクエストコンテキスト を有効化することもできます。ただし、一部の CDI Bean はまだ使用可能な状態でない場合があります。
この解決策の例外として、アプリケーションエンドポイントが 設定を使用した認可 で保護されている場合があります。詳細は、「Web エンドポイントの認可」ガイドの HttpSecurityPolicy への RequestScoped Bean の注入 セクションを参照してください。
4.2. 認証例外レンスポンスをカスタマイズする
Jakarta REST ExceptionMapper
を使用して、io.quarkus.security.AuthenticationFailedException
などの Quarkus Security 認証例外をキャプチャーできます。以下に例を示します。
package io.quarkus.it.keycloak; import jakarta.annotation.Priority; import jakarta.ws.rs.Priorities; import jakarta.ws.rs.core.Context; import jakarta.ws.rs.core.Response; import jakarta.ws.rs.core.UriInfo; import jakarta.ws.rs.ext.ExceptionMapper; import jakarta.ws.rs.ext.Provider; import io.quarkus.security.AuthenticationFailedException; @Provider @Priority(Priorities.AUTHENTICATION) public class AuthenticationFailedExceptionMapper implements ExceptionMapper<AuthenticationFailedException> { @Context UriInfo uriInfo; @Override public Response toResponse(AuthenticationFailedException exception) { return Response.status(401).header("WWW-Authenticate", "Basic realm=\"Quarkus\"").build(); } }
一部の HTTP 認証メカニズムでは、正しい認証チャレンジを作成するために、認証例外を自ら処理する必要があります。たとえば、OpenID Connect (OIDC) 認可コードフロー認証を管理する io.quarkus.oidc.runtime.CodeAuthenticationMechanism
は、正しいリダイレクト URL を作成し、状態 Cookie を設定する必要があります。したがって、カスタム例外マッパーを使用して、このようなメカニズムによって出力される認証例外をカスタマイズしないでください。代わりのより安全なアプローチとして、プロアクティブ認証を有効にして Vert.x HTTP ルート失敗ハンドラーを使用できます。なぜなら、イベントは正しいレスポンスステータスとヘッダーとともにハンドラーに送信されるからです。次に、レンスポンスのみをカスタマイズする必要があります。以下はその例です。
package io.quarkus.it.keycloak; import jakarta.enterprise.context.ApplicationScoped; import jakarta.enterprise.event.Observes; import io.quarkus.security.AuthenticationFailedException; import io.vertx.core.Handler; import io.vertx.ext.web.Router; import io.vertx.ext.web.RoutingContext; @ApplicationScoped public class AuthenticationFailedExceptionHandler { public void init(@Observes Router router) { router.route().failureHandler(new Handler<RoutingContext>() { @Override public void handle(RoutingContext event) { if (event.failure() instanceof AuthenticationFailedException) { event.response().end("CUSTOMIZED_RESPONSE"); } else { event.next(); } } }); } }