Web エンドポイントの認可


Red Hat build of Quarkus 3.20

Red Hat Customer Content Services

概要

このガイドでは、設定ベースとアノテーションベースの両方の方法に重点を置いて、Web エンドポイントの認可メカニズムを説明します。組み込みポリシーとカスタムポリシーの使用、パスとメソッドのマッチング、複雑なパスシナリオの処理など、認可の設定を説明します。次に、ロールベースのアクセス制御と権限管理の詳細を説明し、アクセス拒否のプロパティー、権限の無効化、SecurityIdentity へのロールマッピングを説明します。最後に、標準的なセキュリティーアノテーションとそのアプリケーションに重点を置いて、RESTful サービスを保護するためのアノテーションの使用を説明します。

Red Hat build of Quarkus ドキュメントへのフィードバックの提供

エラーを報告したり、ドキュメントを改善したりするには、Red Hat Jira アカウントにログインし、課題を送信してください。Red Hat Jira アカウントをお持ちでない場合は、アカウントを作成するように求められます。

手順

  1. 次のリンクをクリックして チケットを作成します
  2. Summary に課題の簡単な説明を入力します。
  3. Description に課題や機能拡張の詳細な説明を入力します。問題があるドキュメントのセクションへの URL も記載してください。
  4. Submit をクリックすると、課題が作成され、適切なドキュメントチームに転送されます。

第1章 Web エンドポイントの認可

Quarkus には、プラグ可能な Web セキュリティーレイヤーが組み込まれています。セキュリティーを有効にすると、システムはすべての HTTP リクエストに対して権限チェックを実行し、リクエストを続行するかどうかを決定します。

quarkus.http.auth. 設定によってパスが制限されている場合は、@PermitAll を使用してもパスは開きません。特定のパスにアクセスできるようにするには、Quarkus のセキュリティー設定内で適切な設定を行う必要があります。

注記

Jakarta RESTful Web サービスを使用する場合は、HTTP パスレベルのマッチングではなく、quarkus.security.jaxrs.deny-unannotated-endpoints または quarkus.security.jaxrs.default-roles-allowed を使用してデフォルトのセキュリティー要件を設定することを検討してください。アノテーションにより、個々のエンドポイントでこれらのプロパティーをオーバーライドできるためです。

認可は、セキュリティープロバイダーが提供するユーザーロールに基づいて行われます。ユーザーロールをカスタマイズするには、SecurityIdentityAugmentor を作成します。Security Identity Customization を参照してください。

1.1. 設定を使用した認可

権限は、Quarkus 設定で権限セットによって定義されます。各権限セットで、アクセス制御用のポリシーを指定します。

表1.1 Red Hat build of Quarkus のポリシーの概要
組み込みのポリシー説明

deny

このポリシーはすべてのユーザーを拒否します。

permit

このポリシーはすべてのユーザーを許可します。

authenticated

このポリシーは認証済みユーザーのみを許可します。

特定のロールを持つユーザーにリソースへのアクセスを許可するロールベースのポリシーを定義できます。

ロールベースのポリシーの例

quarkus.http.auth.policy.role-policy1.roles-allowed=user,admin                  1

1
これは、user ロールと admin ロールを持つユーザーを許可するロールベースのポリシーを定義します。

次の設定例に示すように、application.properties ファイルで定義されている組み込みの権限セットを設定することで、カスタムポリシーを参照できます。

ポリシー設定の例

quarkus.http.auth.permission.permit1.paths=/public/*                            1
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET

quarkus.http.auth.permission.deny1.paths=/forbidden                             2
quarkus.http.auth.permission.deny1.policy=deny

quarkus.http.auth.permission.roles1.paths=/roles-secured/*,/other/*,/api/*      3
quarkus.http.auth.permission.roles1.policy=role-policy1

1
この権限は、デフォルトの組み込みの permit ポリシーを参照して、/public への GET メソッドを許可します。この場合、このリクエストはいずれにせよ許可されるため、上記の設定はこの例に影響しません。
2
この権限は、/forbidden パスと /forbidden/ パスの両方の組み込み deny ポリシーを参照します。末尾が * でないため、これはパスの完全一致です。
3
この権限セットは、以前に定義されたポリシーを参照します。roles1 は例の名前です。権限セットには任意の名前を付けることができます。
重要

上記の例の正確なパスパターン /forbidden は、/forbidden/ パスも保護します。この方法では、以下の例の forbidden エンドポイントは deny1 権限により保護されます。

package org.acme.crud;

import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@Path("/forbidden")
public class ForbiddenResource {
    @GET
    public String forbidden() { 1
        return "No!";
    }
}
1
forbidden エンドポイントを保護するには、/forbidden パスと /forbidden/ パスの両方を保護する必要があります。

/forbidden/ パスへのアクセスを許可する必要がある場合は、以下の例のように、より具体的な正確なパスを使用して新しい権限を追加してください。

quarkus.http.auth.permission.permit1.paths=/forbidden/ 1
quarkus.http.auth.permission.permit1.policy=permit
1
/forbidden/ パスは保護されていません。

1.1.1. カスタムの HttpSecurityPolicy

場合に応じて、独自の名前付きポリシーを登録すると便利です。これを実行するには、io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy インターフェイスを実装するアプリケーションスコープの CDI Bean を作成します。以下にその例を示します。

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;

@ApplicationScoped
public class CustomNamedHttpSecPolicy implements HttpSecurityPolicy {
    @Override
    public Uni<CheckResult> checkPermission(RoutingContext event, Uni<SecurityIdentity> identity,
            AuthorizationRequestContext requestContext) {
        if (customRequestAuthorization(event)) {
            return CheckResult.permit();
        }
        return CheckResult.deny();
    }

    @Override
    public String name() {
        return "custom"; 1
    }

    private static boolean customRequestAuthorization(RoutingContext event) {
        // here comes your own security check
        return !event.request().path().endsWith("denied");
    }
}
1
名前付き HTTP セキュリティーポリシーは、application.properties パスマッチングルールにマッチするリクエストにのみ適用されます。

設定ファイルから参照されるカスタム名の HttpSecurityPolicy の例

quarkus.http.auth.permission.custom1.paths=/custom/*
quarkus.http.auth.permission.custom1.policy=custom                              1

1
カスタムポリシー名は、io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy.name メソッドにより返される値とマッチする必要があります。

または、@AuthorizationPolicy セキュリティーアノテーションを使用して、カスタム名 HttpSecurityPolicy を Jakarta REST エンドポイントにバインドすることもできます。

Jakarta REST エンドポイントにバインドされたカスタム名の HttpSecurityPolicy の例

import io.quarkus.vertx.http.security.AuthorizationPolicy;
import jakarta.annotation.security.DenyAll;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@DenyAll 1
@Path("hello")
public class HelloResource {

    @AuthorizationPolicy(name = "custom") 2
    @GET
    public String hello() {
        return "hello";
    }

}

1
@AuthorizationPolicy アノテーションは、他の標準セキュリティーアノテーションと一緒に使用できます。通常どおり、メソッドレベルのアノテーションはクラスレベルのアノテーションよりも優先されます。
2
カスタム名の HttpSecurityPolicy を Jakarta REST hello エンドポイントに適用します。
ヒント

すべてのリクエストで呼び出されるグローバルの HttpSecurityPolicy を作成することもできます。io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy.name メソッドを実装せず、ポリシーに名前を付けないままにしてください。

1.1.2. HttpSecurityPolicy への @RequestScoped Bean の注入

@RequestScoped Bean は、CDI リクエストコンテキスト がアクティブな場合にのみ注入できます。コンテキストは、@ActivateRequestContext などを使用してユーザーがアクティブ化できますが、Quarkus がいくつかの @RequestScoped Bean を準備する前に、認可が行われます。CDI リクエストコンテキストは、Quarkus にアクティブ化および準備させることを推奨します。たとえば、jakarta.ws.rs.core.UriInfo Bean などの Jakarta REST コンテキストから Bean を注入する状況を考えてみましょう。この場合、HttpSecurityPolicy を Jakarta REST エンドポイントに適用する必要があります。これは、次のいずれかの方法で実現できます。* @AuthorizationPolicy セキュリティーアノテーションを使用する。* quarkus.http.auth.permission.custom1.applies-to=jaxrs 設定プロパティーを設定する。

1.1.3. パスとメソッドのマッチング

権限セットでは、パスとメソッドをコンマ区切りリスト形式で指定することもできます。パスの末尾がワイルドカード * の場合は、そのパスによって生成されたクエリーがすべてのサブパスにマッチします。それ以外の場合は、クエリーが完全一致を照会し、特定のパスにのみマッチします。

quarkus.http.auth.permission.permit1.paths=/public*,/css/*,/js/*,/robots.txt    1
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD
1
パスの末尾の * ワイルドカードは、0 個以上のパスセグメントにマッチしますが、/public パスから始まる単語にはマッチしません。そのため、/public-info のようなパスはこのパターンにマッチしません。

1.1.4. パスにはマッチするがメソッドにはマッチしない場合

パスに基づいて 1 つ以上の権限セットにマッチしても、必要なメソッドのいずれにもマッチしないと、リクエストは拒否されます。

ヒント

上記の権限セットが指定されていると、GET/public/foo は、パスとメソッドの両方にマッチするため、許可されます。対照的に、POST/public/foo は、パスにはマッチしますが、メソッドにはマッチしないため、拒否されます。

1.1.5. 複数のパスのマッチング: 最長パスが優先される

マッチングは、常に "最長パスが優先される" という基準で行われます。より詳細な権限セットがマッチした場合、それよりも詳細でない権限セットは考慮されません。

quarkus.http.auth.permission.permit1.paths=/public/*
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD

quarkus.http.auth.permission.deny1.paths=/public/forbidden-folder/*
quarkus.http.auth.permission.deny1.policy=deny
ヒント

上記の権限セットの場合、GET /public/forbidden-folder/foo は、両方の権限セットのパスとマッチします。しかし、より長いパスが deny1 権限セットのパスとマッチするため、deny1 が選択され、リクエストが拒否されます。

注記

前述の deny1 権限と permit1 権限の例で示したように、サブパスの権限がルートパスの権限よりも優先されます。

このルールをさらに例示するために、サブパス権限ではパブリックリソースへのアクセスを許可し、ルートパス権限では認可を要求するシナリオを示します。

quarkus.http.auth.policy.user-policy.roles-allowed=user
quarkus.http.auth.permission.roles.paths=/api/*
quarkus.http.auth.permission.roles.policy=user-policy

quarkus.http.auth.permission.public.paths=/api/noauth/*
quarkus.http.auth.permission.public.policy=permit

1.1.6. 複数のサブパスのマッチング: * ワイルドカードへの最長パスが優先される

前の例では、パスの末尾が * ワイルドカードの場合に、すべてのサブパスがマッチすることを示しました。

このワイルドカードは、パスの途中にも適用され、単一のパスセグメントを表します。他のパスセグメント文字と混在させることはできません。したがって、/public/*/about-us パスのように、* ワイルドカードは常にパス区切り文字によって囲まれます。

複数のパスパターンが同じリクエストパスに対応する場合、システムは * ワイルドカードに至る最長のサブパスを選択します。この場合は、すべてのパスセグメント文字が * ワイルドカードよりも詳細なものとして扱われます。

以下は簡単な例です。

quarkus.http.auth.permission.secured.paths=/api/*/detail                    1
quarkus.http.auth.permission.secured.policy=authenticated
quarkus.http.auth.permission.public.paths=/api/public-product/detail        2
quarkus.http.auth.permission.public.policy=permit
1
/api/product/detail などのリクエストパスには、認証済みユーザーのみがアクセスできます。
2
パス /api/public-product/detail はより詳細であるため、どのユーザーもアクセスできます。
重要

認可を使用した設定で保護するパスは、すべてテストする必要があります。複数のワイルドカードを使用してパスパターンを記述するのは、手間がかかる場合があります。パスが意図したとおりに認可されていることを確認してください。

次の例では、パスは最も詳細なものから最も詳細でないものの順に並べられています。

最も詳細なパスから最も詳細でないパスの順に並べたリクエストパス /one/two/three/four/five のマッチ

/one/two/three/four/five
/one/two/three/four/*
/one/two/three/*/five
/one/two/three/*/*
/one/two/*/four/five
/one/*/three/four/five
/*/two/three/four/five
/*/two/three/*/five
/*

重要

パスの末尾の * ワイルドカードは、0 個以上のパスセグメントとマッチします。その他の場所に指定された * ワイルドカードは、1 つのパスセグメントに完全一致します。

1.1.7. 複数のパスのマッチング: 最も詳細なメソッドが優先される

パスが複数の権限セットに登録されている場合は、リクエストにマッチする HTTP メソッドを明示的に指定している権限セットが優先されます。この場合、メソッドのない権限セットが適用されるのは、リクエストメソッドがメソッドの指定を持つ権限セットとマッチしない場合に限られます。

quarkus.http.auth.permission.permit1.paths=/public/*
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD

quarkus.http.auth.permission.deny1.paths=/public/*
quarkus.http.auth.permission.deny1.policy=deny
注記

上記の権限セットは、GET/public/foo が両方の権限セットのパスにマッチすることを示しています。ただし、これは permit1 権限セットの明示的なメソッドと明確に一致しています。したがって、permit1 が選択され、リクエストが受け入れられます。

対照的に、PUT/public/foo は、permit1 のメソッド権限とマッチしません。その結果、deny1 がアクティブになり、リクエストが拒否されます。

1.1.8. 複数のパスとメソッドのマッチング: どちらも優先される

場合に応じて、前述のルールにより、複数の権限セットが同時に適用されることがあります。その場合、リクエストを続行するには、すべての権限でアクセスが許可されている必要があります。これを実現するには、両方にメソッドを追加するか、両方からメソッドを除外する必要があります。メソッド固有のマッチが優先されます。

quarkus.http.auth.policy.user-policy1.roles-allowed=user
quarkus.http.auth.policy.admin-policy1.roles-allowed=admin

quarkus.http.auth.permission.roles1.paths=/api/*,/restricted/*
quarkus.http.auth.permission.roles1.policy=user-policy1

quarkus.http.auth.permission.roles2.paths=/api/*,/admin/*
quarkus.http.auth.permission.roles2.policy=admin-policy1
ヒント

上記の権限セットの場合、GET /api/foo は両方の権限セットのパスにマッチするため、useradmin の両方のロールが必要です。

1.1.9. アクセスを拒否するための設定プロパティー

次の設定は、ロールベースのアクセス制御 (RBAC) の拒否動作を変更するものです。

quarkus.security.jaxrs.deny-unannotated-endpoints=true|false
true に設定すると、すべての Jakarta REST エンドポイントへのアクセスがデフォルトで拒否されます。Jakarta REST エンドポイントにセキュリティーアノテーションがない場合は、エンドポイントのデフォルトが @DenyAll 動作になります。これにより、保護されているはずのエンドポイントが誤って公開されることを回避できます。デフォルトは false です。
quarkus.security.jaxrs.default-roles-allowed=role1,role2
アノテーションのないエンドポイントのデフォルトのロール要件を定義します。** ロールは、すべての認証済みユーザーを意味する特別なロールです。これを deny-unannotated-endpoints と組み合わせることはできません。代わりに deny が有効になるためです。
quarkus.security.deny-unannotated-members=true|false
true に設定すると、セキュリティーアノテーションを持たないが、セキュリティーアノテーションを持つメソッドを含むクラスで定義されているすべての CDI メソッドと Jakarta REST エンドポイントへのアクセスが拒否されます。デフォルトは false です。

1.1.10. 権限の無効化

次のように、宣言された各権限に対して enabled プロパティーを設定することで、ビルド時に権限を無効にできます。

quarkus.http.auth.permission.permit1.enabled=false
quarkus.http.auth.permission.permit1.paths=/public/*,/css/*,/js/*,/robots.txt
quarkus.http.auth.permission.permit1.policy=permit
quarkus.http.auth.permission.permit1.methods=GET,HEAD

権限は、システムプロパティーまたは環境変数 (例: -Dquarkus.http.auth.permission.permit1.enabled=true) を使用して実行時に再度有効にできます。

1.1.11. 権限パスと HTTP ルートパス

quarkus.http.root-path 設定プロパティーは、http エンドポイントのコンテキストパス を変更します。

デフォルトでは、quarkus.http.root-path は設定した権限パスの先頭に自動的に追加されるため、スラッシュを使用しないでください。次に例を示します。

quarkus.http.auth.permission.permit1.paths=public/*,css/*,js/*,robots.txt

この設定は次のものと同等です。

quarkus.http.auth.permission.permit1.paths=${quarkus.http.root-path}/public/*,${quarkus.http.root-path}/css/*,${quarkus.http.root-path}/js/*,${quarkus.http.root-path}/robots.txt

先頭にスラッシュを付けると、設定された権限パスの解釈方法が変わります。設定された URL がそのまま使用され、quarkus.http.root-path の値が変更されても、パスが調整されません。

例:

quarkus.http.auth.permission.permit1.paths=/public/*,css/*,js/*,robots.txt

この設定は、固定または静的 URL /public から提供されるリソースにのみ影響します。この URL は、quarkus.http.root-path/ 以外に設定されていると、アプリケーションリソースとマッチしない可能性があります。

詳細は、Path Resolution in Quarkus を参照してください。

1.1.12. SecurityIdentity ロールのマッピング

優先されるロールベースのポリシーにより、SecurityIdentity ロールをデプロイメント固有のロールにマッピングできます。その後、デプロイメント固有のロールを、@RolesAllowed アノテーションを使用してエンドポイント認可に適用できます。

quarkus.http.auth.policy.admin-policy1.roles.admin=Admin1 1
quarkus.http.auth.permission.roles1.paths=/* 2
quarkus.http.auth.permission.roles1.policy=admin-policy1
1
admin ロールを Admin1 ロールにマッピングします。SecurityIdentityadminAdmin1 の両方のロールが付与されます。
2
/* パスは保護されており、認証された HTTP リクエストのみにアクセスが許可されます。

パスに関係なく、SecurityIdentity ロールをデプロイメント固有のロールにマップするだけの場合は、次のようにすることもできます。

quarkus.http.auth.roles-mapping.admin=Admin1 1 2
1
admin ロールを Admin1 ロールにマッピングします。SecurityIdentityadminAdmin1 の両方のロールが付与されます。
2
/* パスは保護されていません。標準のセキュリティーアノテーションを使用してエンドポイントを保護するか、この設定プロパティーに加えて HTTP 権限を定義する必要があります。

1.1.13. 共有権限チェック

非共有権限チェックの重要なルールの 1 つは、最も詳細なパスのマッチが 1 つだけ適用されることです。もちろん、同じ優先パスを持つ権限を必要なだけ指定することができます。それらはすべて適用されます。しかし、何度も繰り返さずに、権限チェックを多くのパスに適用したいという場合もあるでしょう。そのような場合は、共有権限チェックが有用です。共有権限チェックは、権限パスがマッチしたときに常に適用されます。

すべての HTTP リクエストに適用されるカスタム名の HttpSecurityPolicy の例

quarkus.http.auth.permission.custom1.paths=/*
quarkus.http.auth.permission.custom1.shared=true    1
quarkus.http.auth.permission.custom1.policy=custom

quarkus.http.auth.policy.admin-policy1.roles-allowed=admin
quarkus.http.auth.permission.roles1.paths=/admin/*
quarkus.http.auth.permission.roles1.policy=admin-policy1

1
カスタムの HttpSecurityPolicy も、admin-policy1 ポリシーとともに /admin/1 パスに適用されます。
ヒント

共有権限チェックを多数設定することは、非共有権限チェックを設定する場合よりも効果が低くなります。以下の例のように、共有権限を使用して非共有権限チェックを補完してください。

共有権限を持つ SecurityIdentity ロールのマッピング

quarkus.http.auth.policy.role-policy1.roles.root=admin,user 1
quarkus.http.auth.permission.roles1.paths=/secured/*        2
quarkus.http.auth.permission.roles1.policy=role-policy1
quarkus.http.auth.permission.roles1.shared=true

quarkus.http.auth.policy.role-policy2.roles-allowed=user    3
quarkus.http.auth.permission.roles2.paths=/secured/user/*
quarkus.http.auth.permission.roles2.policy=role-policy2

quarkus.http.auth.policy.role-policy3.roles-allowed=admin
quarkus.http.auth.permission.roles3.paths=/secured/admin/*
quarkus.http.auth.permission.roles3.policy=role-policy3

1
ロール root は、/secured/user/* および /secured/admin/* パスにアクセスできるようになります。
2
/secured/* パスには認証済みユーザーのみがアクセスできます。これにより、/secured/all パスなどが保護されます。
3
共有権限は常に非共有権限の前に適用されるため、root ロールを持つ SecurityIdentity には user ロールも付与されます。

1.2. アノテーションを使用した認可

Red Hat build of Quarkus には、REST エンドポイントと CDI Bean 上の共通セキュリティーアノテーション @RolesAllowed@DenyAll@PermitAll に基づく ロールベースのアクセス制御 (RBAC) を可能にするセキュリティーが組み込まれています。

表1.2 Red Hat build of Quarkus のアノテーションタイプの概要
アノテーションタイプ説明

@DenyAll

どのセキュリティーロールも指定のメソッドを呼び出すことができないことを指定します。

@PermitAll

すべてのセキュリティーロールが指定のメソッドを呼び出せることを指定します。

@PermitAll は認証なしですべてのユーザーにアクセスを許可します。

@RolesAllowed

アプリケーション内のメソッドへのアクセスを許可するセキュリティーロールのリストを指定します。

@Authenticated

Red Hat build of Quarkus は、認証されたすべてのユーザーがリソースにアクセスできるようにする io.quarkus.security.Authenticated アノテーションを提供します。これは @RolesAllowed("**") と同等です。

@PermissionsAllowed

指定されたメソッドを呼び出すことが許可される権限のリストを指定します。

@AuthorizationPolicy

指定された Jakarta REST エンドポイントへのアクセスを許可する名前付きの io.quarkus.vertx.http.runtime.security.HttpSecurityPolicy を指定します。名前付き HttpSecurityPolicy は、Jakarta REST エンドポイントにバインドされたカスタムの名前付き HttpSecurityPolicy の例 に示されているように、一般的な認可チェックに使用できます。

次の SubjectExposingResource の例は、エンドポイントの記述および保護に Jakarta REST と Common Security アノテーションの両方を使用するエンドポイントを示しています。

SubjectExposingResource の例

import java.security.Principal;

import jakarta.annotation.security.DenyAll;
import jakarta.annotation.security.PermitAll;
import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;

@Path("subject")
public class SubjectExposingResource {

    @GET
    @Path("secured")
    @RolesAllowed("Tester") 1
    public String getSubjectSecured(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal(); 2
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("authenticated")
    @Authenticated 3
    public String getSubjectAuthenticated(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("unsecured")
    @PermitAll 4
    public String getSubjectUnsecured(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal(); 5
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }

    @GET
    @Path("denied")
    @DenyAll 6
    public String getSubjectDenied(@Context SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }
}

1
/subject/secured エンドポイントは、@RolesAllowed("Tester") アノテーションを使用して "Tester" ロールが付与された認証済みユーザーを必要とします。
2
エンドポイントは、Jakarta REST SecurityContext からユーザープリンシパルを取得します。これは、保護されたエンドポイントに対して non-null を返します。
3
/subject/authenticated エンドポイントでは、@Authenticated アノテーションを指定して、認証されたすべてのユーザーを許可します。
4
/subject/unsecured エンドポイントは、@PermitAll アノテーションを指定することにより、認証されていないアクセスを許可します。
5
ユーザープリンシパルを取得する呼び出しは、呼び出し元が認証されていない場合は null を返し、呼び出し元が認証されている場合は non-null を返します。
6
/subject/denied エンドポイントは、@DenyAll アノテーションを宣言することにより、呼び出し元のユーザーに関係なく、REST メソッドとしての直接アクセスをすべて禁止します。このメソッドは、このクラスの他のメソッドによって内部的に呼び出すことができます。
注意

IO スレッドで標準のセキュリティーアノテーションを使用する予定の場合は、プロアクティブ認証 の情報を確認してください。

@RolesAllowed アノテーション値は、デフォルト値やネストされたプロパティー式を含む プロパティー式 をサポートします。アノテーションで使用される設定プロパティーは実行時に解決されます。

表1.3 アノテーション値の例
アノテーション値の説明

@RolesAllowed("${admin-role}")

エンドポイントは、admin-role プロパティーの値によって示されるロールを持つユーザーを許可します。

@RolesAllowed("${tester.group}-${tester.role}")

値に複数の変数を含めることができることを示す例。

@RolesAllowed("${customer:User}")

デフォルト値の例示。必要なロールを、customer プロパティーの値によって示します。ただし、このプロパティーが指定されていない場合は、デフォルトで User という名前のロールが必要になります。

@RolesAllowed アノテーションでのプロパティー式の使用例

admin=Administrator
tester.group=Software
tester.role=Tester
%prod.secured=User
%dev.secured=**
all-roles=Administrator,Software,Tester,User

サブジェクトアクセス制御の例

import java.security.Principal;

import jakarta.annotation.security.RolesAllowed;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;

@Path("subject")
public class SubjectExposingResource {

    @GET
    @Path("admin")
    @RolesAllowed("${admin}") 1
    public String getSubjectSecuredAdmin(@Context SecurityContext sec) {
        return getUsername(sec);
    }

    @GET
    @Path("software-tester")
    @RolesAllowed("${tester.group}-${tester.role}") 2
    public String getSubjectSoftwareTester(@Context SecurityContext sec) {
        return getUsername(sec);
    }

    @GET
    @Path("user")
    @RolesAllowed("${customer:User}") 3
    public String getSubjectUser(@Context SecurityContext sec) {
        return getUsername(sec);
    }

    @GET
    @Path("secured")
    @RolesAllowed("${secured}") 4
    public String getSubjectSecured(@Context SecurityContext sec) {
        return getUsername(sec);
    }

    @GET
    @Path("list")
    @RolesAllowed("${all-roles}") 5
    public String getSubjectList(@Context SecurityContext sec) {
        return getUsername(sec);
    }

    private String getUsername(SecurityContext sec) {
        Principal user = sec.getUserPrincipal();
        String name = user != null ? user.getName() : "anonymous";
        return name;
    }
}

1
@RolesAllowed アノテーションの値は、Administrator という値に設定されます。
2
この /subject/software-tester エンドポイントには、"Software-Tester" ロールが付与された認証済みユーザーが必要です。ロールの定義では複数の式を使用できます。
3
この /subject/user エンドポイントには、@RolesAllowed("${customer:User}") アノテーションを使用して "User" ロールが付与された認証済みユーザーが必要です。これは、設定プロパティー customer を設定しなかったためです。
4
実稼働環境では、この /subject/secured エンドポイントには、User ロールを持つ認証済みユーザーが必要です。開発モードでは、すべての認証済みユーザーが許可されます。
5
プロパティー式 all-roles は、コレクション型 List として扱われます。そのため、このエンドポイントには、AdministratorSoftwareTesterUser の各ロールがアクセスできるようになります。

1.2.1. エンドポイントセキュリティーアノテーションと Jakarta REST 継承

Quarkus は、次の例のようにエンドポイント実装またはそのクラスに配置されたセキュリティーアノテーションをサポートしています。

@Path("hello")
public interface HelloInterface {

    @GET
    String hello();

}

@DenyAll 1
public class HelloInterfaceImpl implements HelloInterface {

    @RolesAllowed("admin") 2
    @Override
    public String hello() {
        return "Hello";
    }
}
1
クラスレベルのセキュリティーアノテーションは、エンドポイント実装が宣言されているクラスに配置する必要があります。
2
メソッドレベルのセキュリティーアノテーションはエンドポイント実装に配置する必要があります。
重要

デフォルトのインターフェイスメソッドとして宣言された RESTEasy サブリソースロケーターは、標準のセキュリティーアノテーションでは保護できません。保護されたサブリソースロケータは、次の例のように、インターフェイス実装者に実装され、保護される必要があります。

@Path("hello")
public interface HelloInterface {

    @RolesAllowed("admin")
    @Path("sub")
    default HelloSubResource wrongWay() {
        // not supported
    }

    @Path("sub")
    HelloSubResource rightWay();

}

public class HelloInterfaceImpl implements HelloInterface {

    @RolesAllowed("admin")
    @Override
    public HelloSubResource rightWay() {
        return new HelloSubResource();
    }
}

1.2.2. 権限のアノテーション

Quarkus は、指定の権限を持つ認証済みユーザーにリソースへのアクセスを許可する io.quarkus.security.PermissionsAllowed アノテーションも備えています。このアノテーションは、一般的なセキュリティーアノテーションの拡張であり、SecurityIdentity インスタンスに付与された権限をチェックします。

@PermissionsAllowed アノテーションで保護されたエンドポイントの例

package org.acme.crud;

import io.quarkus.arc.Arc;
import io.vertx.ext.web.RoutingContext;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.QueryParam;

import io.quarkus.security.PermissionsAllowed;

import java.security.BasicPermission;
import java.security.Permission;
import java.util.Collection;
import java.util.Collections;

@Path("/crud")
public class CRUDResource {

    @PermissionsAllowed("create") 1
    @PermissionsAllowed("update")
    @POST
    @Path("/modify/repeated")
    public String createOrUpdate() {
        return "modified";
    }

    @PermissionsAllowed(value = {"create", "update"}, inclusive=true) 2
    @POST
    @Path("/modify/inclusive")
    public String createOrUpdate(Long id) {
        return id + " modified";
    }

    @PermissionsAllowed({"see:detail", "see:all", "read"}) 3
    @GET
    @Path("/id/{id}")
    public String getItem(String id) {
        return "item-detail-" + id;
    }

    @PermissionsAllowed(value = "list", permission = CustomPermission.class) 4
    @Path("/list")
    @GET
    public Collection<String> list(@QueryParam("query-options") String queryOptions) {
        // your business logic comes here
        return Collections.emptySet();
    }

    public static class CustomPermission extends BasicPermission {

        public CustomPermission(String name) {
            super(name);
        }

        @Override
        public boolean implies(Permission permission) {
            var event = Arc.container().instance(RoutingContext.class).get(); 5
            var publicContent = "public-content".equals(event.request().params().get("query-options"));
            var hasPermission = getName().equals(permission.getName());
            return hasPermission && publicContent;
        }
    }
}

1
リソースメソッド createOrUpdate にアクセスできるのは、create 権限と update 権限の両方を持つユーザーのみです。
2
デフォルトでは、1 つのアノテーションインスタンスを通じて指定された権限のうち、少なくとも 1 つの権限が必要です。inclusive=true を設定することで、すべての権限を必須にできます。両方のリソースメソッド createOrUpdate に、同等の認可要件があります。
3
SecurityIdentityread 権限または see 権限と、all アクションまたは detail アクションのどちらかがある場合は、getItem へのアクセスが許可されます。
4
任意の java.security.Permission 実装を使用できます。デフォルトでは、文字列ベースの権限は io.quarkus.security.StringPermission により実行されます。
5
権限は Bean ではないため、Bean インスタンスを取得する唯一の方法は、Arc.container() を使用してプログラム的に取得することです。
注意

IO スレッドで @PermissionsAllowed を使用する予定の場合は、プロアクティブ認証 の情報を確認してください。

注記

Quarkus インターセプターの制限により、@PermissionsAllowed をクラスレベルで繰り返すことはできません。詳細は、Quarkus の「CDI reference」ガイドの Repeatable interceptor bindings セクションを参照してください。

ロールが有効な SecurityIdentity インスタンスに権限を追加する最も簡単な方法は、ロールを権限にマッピングすることです。次の例に示すように、設定を使用した認可 を使用して、認可されたリクエストに、CRUDResource エンドポイントに必要な SecurityIdentity 権限を付与します。

quarkus.http.auth.policy.role-policy1.permissions.user=see:all                                      1
quarkus.http.auth.policy.role-policy1.permissions.admin=create,update,read                          2
quarkus.http.auth.permission.roles1.paths=/crud/modify/*,/crud/id/*                                 3
quarkus.http.auth.permission.roles1.policy=role-policy1

quarkus.http.auth.policy.role-policy2.permissions.user=list
quarkus.http.auth.policy.role-policy2.permission-class=org.acme.crud.CRUDResource$CustomPermission  4
quarkus.http.auth.permission.roles2.paths=/crud/list
quarkus.http.auth.permission.roles2.policy=role-policy2
1
user ロールの SecurityIdentity インスタンスに、see 権限と all アクションを追加します。同様に、@PermissionsAllowed アノテーションには、io.quarkus.security.StringPermission がデフォルトで使用されます。
2
create 権限、update 権限、および read 権限が、admin ロールにマッピングされます。
3
ロールポリシー role-policy1 は、認証されたリクエストのみが /crud/modify および /crud/id サブパスにアクセスできるようにします。パスマッチングアルゴリズムの詳細は、このガイドで後述する 複数のパスのマッチング: 最長パスが優先される を参照してください。
4
java.security.Permission クラスのカスタム実装を指定できます。カスタムクラスでは、権限名とアクション (任意) を受け入れるコンストラクター (String 配列など) を 1 つだけ定義する必要があります。この場合は、権限 listnew CustomPermission("list") として SecurityIdentity インスタンスに追加されます。

追加のコンストラクターパラメーターを使用して、カスタム java.security.Permission クラスを作成することもできます。これらの追加パラメーター名は、@PermissionsAllowed アノテーションが付けられたメソッドの引数名と一致します。その後、Quarkus が実際の引数を使用してカスタム権限をインスタンス化します。この権限を使用して、@PermissionsAllowed アノテーションが付けられたメソッドが呼び出されます。

追加の引数を受け入れるカスタムの java.security.Permission クラスの例

package org.acme.library;

import java.security.Permission;
import java.util.Arrays;
import java.util.Set;

public class LibraryPermission extends Permission {

    private final Set<String> actions;
    private final Library library;

    public LibraryPermission(String libraryName, String[] actions, Library library) { 1
        super(libraryName);
        this.actions = Set.copyOf(Arrays.asList(actions));
        this.library = library;
    }

    @Override
    public boolean implies(Permission requiredPermission) {
        if (requiredPermission instanceof LibraryPermission) {
            LibraryPermission that = (LibraryPermission) requiredPermission;
            boolean librariesMatch = getName().equals(that.getName());
            boolean requiredLibraryIsSublibrary = library.isParentLibraryOf(that.library);
            boolean hasOneOfRequiredActions = that.actions.stream().anyMatch(actions::contains);
            return (librariesMatch || requiredLibraryIsSublibrary) && hasOneOfRequiredActions;
        }
        return false;
    }

    // here comes your own implementation of the `java.security.Permission` class methods

    public static abstract class Library {

        protected String description;

        abstract boolean isParentLibraryOf(Library library);

    }

    public static class MediaLibrary extends Library {

        @Override
        boolean isParentLibraryOf(Library library) {
            return library instanceof MediaLibrary;
        }
    }

    public static class TvLibrary extends MediaLibrary {
        // TvLibrary specific implementation of the 'isParentLibraryOf' method
    }
}

1
カスタムの Permission クラスのコンストラクターは、1 つだけである必要があります。最初のパラメーターは、常に権限名とみなされ、String 型である必要があります。Quarkus は、必要に応じてコンストラクターに権限アクションを渡すことができます。これを実現するには、2 番目のパラメーターを String[] として宣言します。

LibraryPermission クラスは、SecurityIdentityreadwritelist などの必要なアクションのいずれかを実行することを許可されている場合に、現在のライブラリーまたは親ライブラリーへのアクセスを許可します。

次の例は、LibraryPermission クラスの使用方法を示しています。

package org.acme.library;

import io.quarkus.security.PermissionsAllowed;
import jakarta.enterprise.context.ApplicationScoped;
import org.acme.library.LibraryPermission.Library;

@ApplicationScoped
public class LibraryService {

    @PermissionsAllowed(value = "tv:write", permission = LibraryPermission.class) 1
    public Library updateLibrary(String newDesc, Library library) {
        library.description = newDesc;
        return library;
    }

    @PermissionsAllowed(value = "tv:write", permission = LibraryPermission.class) 2
    @PermissionsAllowed(value = {"tv:read", "tv:list"}, permission = LibraryPermission.class)
    public Library migrateLibrary(Library migrate, Library library) {
        // migrate libraries
        return library;
    }

}
1
仮パラメーター library は、同じ名前の LibraryPermission コンストラクターパラメーターと一致するパラメーターとして識別されます。したがって、Quarkus は library パラメーターを LibraryPermission クラスのコンストラクターに渡します。ただし、updateLibrary メソッドを呼び出すたびに LibraryPermission をインスタンス化する必要があります。
2
ここで、2 番目の Library パラメーターは名前 library と一致しますが、migrate パラメーターは LibraryPermission 権限のインスタンス化中に無視されます。

LibraryPermission で保護されたリソースの例

package org.acme.library;

import io.quarkus.security.PermissionsAllowed;
import jakarta.inject.Inject;
import jakarta.ws.rs.PUT;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.PathParam;
import org.acme.library.LibraryPermission.Library;

@Path("/library")
public class LibraryResource {

    @Inject
    LibraryService libraryService;

    @PermissionsAllowed(value = "tv:write", permission = LibraryPermission.class)
    @PUT
    @Path("/id/{id}")
    public Library updateLibrary(@PathParam("id") Integer id, Library library) {
        ...
    }

    @PUT
    @Path("/service-way/id/{id}")
    public Library updateLibrarySvc(@PathParam("id") Integer id, Library library) {
        String newDescription = "new description " + id;
        return libraryService.updateLibrary(newDescription, library);
    }

}

CRUDResource の例と同様に、次の例は、admin ロールを持つユーザーに MediaLibrary を更新する権限を付与する方法を示しています。

package org.acme.library;

import io.quarkus.runtime.annotations.RegisterForReflection;

@RegisterForReflection 1
public class MediaLibraryPermission extends LibraryPermission {

    public MediaLibraryPermission(String libraryName, String[] actions) {
        super(libraryName, actions, new MediaLibrary());    2
    }

}
1
ネイティブ実行可能ファイルをビルドする場合は、権限クラスをリフレクション用に登録する必要があります。ただし、1 つ以上の io.quarkus.security.PermissionsAllowed#name パラメーターでもその権限クラスが使用されている場合を除きます。@RegisterForReflection アノテーションの詳細は、native application tips ページを参照してください。
2
MediaLibrary インスタンスを LibraryPermission コンストラクターに渡します。
quarkus.http.auth.policy.role-policy3.permissions.admin=media-library:list,media-library:read,media-library:write   1
quarkus.http.auth.policy.role-policy3.permission-class=org.acme.library.MediaLibraryPermission
quarkus.http.auth.permission.roles3.paths=/library/*
quarkus.http.auth.permission.roles3.policy=role-policy3
1
readwrite、および list アクションを許可する権限 media-library を付与します。MediaLibraryTvLibrary クラスの親であるため、admin ロールを持つユーザーも TvLibrary を変更することが許可されます。
ヒント

/library/* パスは、Keycloak プロバイダーの Dev UI ページからテストできます。Dev Services for Keycloak により自動的に作成されるユーザー alice が、admin ロールを持っているためです。

これまでに示した例は、ロールと権限のマッピングを示しています。SecurityIdentity インスタンスには、プログラムで権限を追加することも可能です。次の例では、SecurityIdentity をカスタマイズ して、以前に HTTP ロールベースのポリシーで付与したものと同じ権限を追加します。

プログラムで SecurityIdentityLibraryPermission を追加する例

import java.security.Permission;

import jakarta.enterprise.context.ApplicationScoped;

import io.quarkus.security.identity.AuthenticationRequestContext;
import io.quarkus.security.identity.SecurityIdentity;
import io.quarkus.security.identity.SecurityIdentityAugmentor;
import io.quarkus.security.runtime.QuarkusSecurityIdentity;
import io.smallrye.mutiny.Uni;

@ApplicationScoped
public class PermissionsIdentityAugmentor implements SecurityIdentityAugmentor {

    @Override
    public Uni<SecurityIdentity> augment(SecurityIdentity identity, AuthenticationRequestContext context) {
        if (isNotAdmin(identity)) {
            return Uni.createFrom().item(identity);
        }
        return Uni.createFrom().item(build(identity));
    }

    private boolean isNotAdmin(SecurityIdentity identity) {
        return identity.isAnonymous() || !"admin".equals(identity.getPrincipal().getName());
    }

    SecurityIdentity build(SecurityIdentity identity) {
        return QuarkusSecurityIdentity.builder(identity)
                .addPermission(new MediaLibraryPermission("media-library", new String[] { "read", "write", "list"}); 1
                .build();
    }

}

1
作成された media-library 権限を追加すると、readwrite、および list アクションを実行できます。MediaLibraryTvLibrary クラスの親であるため、admin ロールを持つユーザーも TvLibrary を変更することが許可されます。
注意

アノテーションベースの権限は、カスタムの Jakarta REST SecurityContexts では機能しません。jakarta.ws.rs.core.SecurityContext に権限がないためです。

1.2.2.1. 権限チェッカーを作成する

デフォルトでは、SecurityIdentity は、この ID が @PermissionAllowed 認可制限を通過するかどうかを確認するために使用できる権限で設定されている必要があります。または、@PermissionChecker アノテーションを使用して、任意の CDI Bean メソッドを権限チェッカーとしてマークすることもできます。@PermissionChecker アノテーション値は、@PermissionsAllowed アノテーション値により宣言された必要な権限と一致する必要があります。たとえば、権限チェッカーは次のように作成できます。

package org.acme.security.rest.resource;

import io.quarkus.security.PermissionChecker;
import io.quarkus.security.PermissionsAllowed;
import io.quarkus.security.identity.SecurityIdentity;
import jakarta.ws.rs.POST;
import jakarta.ws.rs.Path;

import org.jboss.resteasy.reactive.RestForm;
import org.jboss.resteasy.reactive.RestPath;

@Path("/project/{projectName}")
public class ProjectResource {

    @PermissionsAllowed("rename-project") 1
    @POST
    public void renameProject(@RestPath String projectName, @RestForm String newName) {
        Project project = Project.findByName(projectName);
        project.name = newName;
    }

    @PermissionChecker("rename-project") 2
    boolean canRenameProject(SecurityIdentity identity, String projectName) { 3 4
        var principalName = identity.getPrincipal().getName();
        var user = User.getUserByName(principalName);
        return userOwnsProject(projectName, user);
    }
}
1
ProjectResource#renameProject にアクセスするために必要な権限は、rename-project 権限です。
2
ProjectResource#canRenameProject メソッドは、ProjectResource#renameProject エンドポイントへのアクセスを承認します。
3
SecurityIdentity インスタンスは、任意の権限チェッカーメソッドに注入できます。
4
この例では、rename-project 権限チェッカーが同じリソースで宣言されています。ただし、次の例に示すように、この権限チェッカーを宣言できる場所に制限はありません。
注記

権限チェッカーメソッドは、通常のスコープの CDI Bean または @Singleton Bean で宣言できます。@Dependent CDI Bean スコープは現在サポートされていません。

上記の権限チェッカーでは、renameProject エンドポイントを承認するために SecurityIdentity インスタンスが必要です。rename-project 権限チェッカーをリソース上で直接宣言する代わりに、次の例のように任意の CDI Bean 上で宣言できます。

package org.acme.security.rest.resource;

import io.quarkus.security.PermissionChecker;
import jakarta.enterprise.context.ApplicationScoped;
import jakarta.inject.Inject;

@ApplicationScoped 1
public class ProjectPermissionChecker {

    @PermissionChecker("rename-project")
    boolean canRenameProject(String projectName, SecurityIdentity identity) {   2
        var principalName = identity.getPrincipal().getName();
        var user = User.getUserByName(principalName);
        return userOwnsProject(projectName, user);
    }

}
1
権限チェッカーを備えた CDI Bean は、通常のスコープ Bean または @Singleton Bean のいずれかである必要があります。
2
権限チェッカーメソッドは、boolean または Uni<Boolean> のいずれかを返す必要があります。プライベートチェッカーメソッドはサポートされていません。
ヒント

権限チェックは、デフォルトでイベントループで実行します。ワーカースレッドでチェックを実行する場合は、権限チェッカーメソッドに io.smallrye.common.annotation.Blocking アノテーションを付けます。

@PermissionsAllowed 値と @PermissionChecker 値のマッチングは、次の例に示すように、文字列が同じかどうかに基づいて行われます。

package org.acme.security;

import io.quarkus.security.PermissionChecker;
import io.quarkus.security.PermissionsAllowed;
import jakarta.enterprise.context.ApplicationScoped;

@ApplicationScoped
public class FileService {

    @PermissionsAllowed({ "delete:all", "delete:dir" }) 1
    void deleteDirectory(Path directoryPath) {
        // delete directory
    }

    @PermissionsAllowed(value = { "delete:service", "delete:file" }, inclusive = true) 2
    void deleteServiceFile(Path serviceFilePath) {
        // delete service file
    }

    @PermissionChecker("delete:all")
    boolean canDeleteAllDirectories(SecurityIdentity identity) {
        String filePermissions = identity.getAttribute("user-group-file-permissions");
        return filePermissions != null && filePermissions.contains("w");
    }

    @PermissionChecker("delete:service")
    boolean canDeleteService(SecurityIdentity identity) {
        return identity.hasRole("admin");
    }

    @PermissionChecker("delete:file")
    boolean canDeleteFile(Path serviceFilePath) {
        return serviceFilePath != null && !serviceFilePath.endsWith("critical");
    }
}
1
権限チェッカーメソッド canDeleteAllDirectories は、delete:all 値が等しいため、deleteDirectory へのアクセスを許可します。
2
権限チェッカーメソッドは 2 つ必要です。1 つは delete:service 権限用、もう 1 つは delete:file 権限用です。
1.2.2.2. 権限メタアノテーションを作成する

@PermissionsAllowed はメタアノテーションでも使用できます。たとえば、新しい @CanWrite セキュリティーアノテーションは次のように作成できます。

import java.lang.annotation.ElementType;
import java.lang.annotation.Retention;
import java.lang.annotation.RetentionPolicy;
import java.lang.annotation.Target;

import io.quarkus.security.PermissionsAllowed;

@Retention(RetentionPolicy.RUNTIME)
@Target({ ElementType.METHOD, ElementType.TYPE })
@PermissionsAllowed(value = "write", permission = CustomPermission.class) 1
public @interface CanWrite {

}
1
@CanWrite アノテーションが付けられたメソッドまたはクラスは、この @PermissionsAllowed アノテーションインスタンスにより保護されます。
1.2.2.3. @BeanParam パラメーターをカスタム権限に渡す

Quarkus は、保護されたメソッドパラメーターのフィールドをカスタム権限コンストラクターパラメーターにマップできます。この機能を使用すると、jakarta.ws.rs.BeanParam パラメーターをカスタム権限に渡すことができます。次の Jakarta REST リソースについて考えてみましょう。

package org.acme.security.rest.resource;

import io.quarkus.security.PermissionsAllowed;
import jakarta.ws.rs.BeanParam;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;

@Path("/hello")
public class HelloResource {

    @PermissionsAllowed(value = "say-hello", params = "beanParam.securityContext.userPrincipal.name") 1
    @GET
    public String sayHello(@BeanParam SimpleBeanParam beanParam) {
        return "Hello from " + beanParam.uriInfo.getPath();
    }

}
1
params アノテーション属性は、ユーザープリンシパル名を BeanParamPermissionChecker#canSayHello メソッドに渡す必要があることを指定します。customAuthorizationHeaderquery などの他の BeanParamPermissionChecker#canSayHello メソッドパラメーターは自動的に一致します。Quarkus は、beanParam フィールドとそのパブリックアクセサーの中から BeanParamPermissionChecker#canSayHello メソッドパラメーターを識別します。あいまいな解決を避けるため、自動検出は beanParam フィールドに対してのみ機能します。そのため、ユーザープリンシパル名へのパスを明示的に指定する必要がありました。

SimpleBeanParam クラスは以下の例のように宣言されています。

package org.acme.security.rest.dto;

import java.util.List;

import jakarta.ws.rs.HeaderParam;
import jakarta.ws.rs.QueryParam;
import jakarta.ws.rs.core.Context;
import jakarta.ws.rs.core.SecurityContext;
import jakarta.ws.rs.core.UriInfo;

public class SimpleBeanParam {

    @HeaderParam("CustomAuthorization")
    private String customAuthorizationHeader;

    @Context
    SecurityContext securityContext;

    @Context
    public UriInfo uriInfo;

    @QueryParam("query")
    public String query;    1

    public SecurityContext getSecurityContext() { 2
        return securityContext;
    }

    public String customAuthorizationHeader() { 3
        return customAuthorizationHeader;
    }
}
1
Quarkus Security は、カスタム権限コンストラクターにパブリックフィールドのみを渡すことができます。
2
Quarkus Security は、パブリックゲッターメソッドが利用可能な場合はそれを自動的に使用します。
3
customAuthorizationHeader フィールドはパブリックではないため、Quarkus は customAuthorizationHeader アクセサーを使用してこのフィールドにアクセスします。これは、生成されたアクセサーに get という接頭辞が付かない Java レコードで特に便利です。

以下は、ユーザープリンシパル、カスタムヘッダー、クエリーパラメーターに基づいて say-hello 権限をチェックする @PermissionChecker メソッドの例です。

package org.acme.security.permission;

import jakarta.enterprise.context.ApplicationScoped;
import io.quarkus.security.PermissionChecker;

@ApplicationScoped
public class BeanParamPermissionChecker {

    @PermissionChecker("say-hello")
    boolean canSayHello(String customAuthorizationHeader, String name, String query) {
        boolean queryParamAllowedForPermissionName = checkQueryParams(query);
        boolean usernameWhitelisted = isUserNameWhitelisted(name);
        boolean customAuthorizationMatches = checkCustomAuthorization(customAuthorizationHeader);
        return queryParamAllowedForPermissionName && usernameWhitelisted && customAuthorizationMatches;
    }

    ...
}
注記

@BeanParam@PermissionChecker メソッドに直接渡し、プログラムでそのフィールドにアクセスできます。@PermissionsAllowed#params 属性を使用して @BeanParam フィールドを参照する機能は、構造が異なる複数の @BeanParam クラスがある場合に便利です。

1.3. 参考資料

法律上の通知

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

詳細情報

試用、購入および販売

コミュニティー

Red Hat ドキュメントについて

Red Hat をお使いのお客様が、信頼できるコンテンツが含まれている製品やサービスを活用することで、イノベーションを行い、目標を達成できるようにします。 最新の更新を見る.

多様性を受け入れるオープンソースの強化

Red Hat では、コード、ドキュメント、Web プロパティーにおける配慮に欠ける用語の置き換えに取り組んでいます。このような変更は、段階的に実施される予定です。詳細情報: Red Hat ブログ.

会社概要

Red Hat は、企業がコアとなるデータセンターからネットワークエッジに至るまで、各種プラットフォームや環境全体で作業を簡素化できるように、強化されたソリューションを提供しています。

© 2024 Red Hat, Inc.