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


Quarkus には、一般的なセキュリティーアノテーション @RolesAllowed@DenyAll、REST エンドポイント、および CDI Bean の@PermitAll に基づいて、ロールベースのアクセス制御(RBAC) を許可する組み込みセキュリティーが含まれています。

注記

quarkus.http.auth 設定の認可チェックは、標準のセキュリティーアノテーションのセキュリティーチェックの前に実行されます。したがって、@PermitAll は、HTTP 権限によって制限されていないパスへのアクセスのみを許可します。@PermitAll は、HTTP レベルのセキュリティー設定をオーバーライドできず、@RolesAllowed などの他の標準セキュリティーアノテーションによって課せられた制限を緩和するだけです。

Expand
表1.2 Quarkus アノテーションタイプの概要
アノテーションタイプ説明

@DenyAll

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

@PermitAll

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

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

@RolesAllowed

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

@Authenticated

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;
    }
}
Copy to Clipboard Toggle word wrap

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 メソッドとしての直接アクセスをすべて禁止します。このメソッドは、このクラスの他のメソッドによって内部的に呼び出すことができます。
Important

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

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

Expand
表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
Copy to Clipboard Toggle word wrap

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

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;
    }
}
Copy to Clipboard Toggle word wrap

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";
    }
}
Copy to Clipboard Toggle word wrap
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();
    }
}
Copy to Clipboard Toggle word wrap

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;
        }
    }
}
Copy to Clipboard Toggle word wrap

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() を使用してプログラム的に取得することです。
Important

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
Copy to Clipboard Toggle word wrap
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
    }
}
Copy to Clipboard Toggle word wrap

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;
    }

}
Copy to Clipboard Toggle word wrap
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);
    }

}
Copy to Clipboard Toggle word wrap

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

    }

}
Copy to Clipboard Toggle word wrap
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
Copy to Clipboard Toggle word wrap
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();
    }

}
Copy to Clipboard Toggle word wrap

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

アノテーションベースの権限は、カスタムの 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);
    }
}
Copy to Clipboard Toggle word wrap
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);
    }

}
Copy to Clipboard Toggle word wrap
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");
    }
}
Copy to Clipboard Toggle word wrap
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 {

}
Copy to Clipboard Toggle word wrap
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();
    }

}
Copy to Clipboard Toggle word wrap
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;
    }
}
Copy to Clipboard Toggle word wrap
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;
    }

    ...
}
Copy to Clipboard Toggle word wrap
注記

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

トップに戻る
Red Hat logoGithubredditYoutubeTwitter

詳細情報

試用、購入および販売

コミュニティー

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

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

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

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

会社概要

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

Theme

© 2025 Red Hat