第4章 プロアクティブ認証
設定のカスタマイズや例外の処理を含め、Quarkus でプロアクティブ認証を管理する方法を説明します。さまざまなアプリケーションシナリオにおける実用的な洞察とストラテジーを得ることができます。
Quarkus では、プロアクティブ認証がデフォルトで有効になっています。これにより、ターゲットページで認証が不要な場合でも、認証情報を持つすべての受信リクエストが必ず認証されます。その結果、ターゲットページが公開されている場合でも、無効な認証情報を持つリクエストは拒否されます。匿名のリクエストが許可されるため、認証情報のないリクエストは拒否されません。
ターゲットページで必要な場合にのみ認証を行う場合は、このデフォルトの動作をオフにできます。ターゲットページで要求される場合にのみ認証を行うためにプロアクティブ認証をオフにするには、application.properties
設定ファイルを次のように変更します。
quarkus.http.auth.proactive=false
Copy to clipboardCopiedプロアクティブ認証をオフにすると、アイデンティティーが要求された場合にのみ認証プロセスが実行されます。ユーザーの認証を必要とするセキュリティールールがある場合、または現在のアイデンティティーへのプログラムによるアクセスが必要な場合、アイデンティティーが要求される場合があります。
プロアクティブ認証が使用されていない場合、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());
}
}
Copy to clipboardCopiedimport jakarta.annotation.security.RolesAllowed;
import jakarta.enterprise.context.ApplicationScoped;
@ApplicationScoped
public class HelloService {
@RolesAllowed("admin")
public String sayHello() {
return "Hello";
}
}
Copy to clipboardCopied4.1. CDI リクエストコンテキストの有効化
場合によっては、認証および認可中に @RequestScoped
Bean を注入する必要があります。代表的な例としては、SecurityIdentity
のオーグメンテーション中にデータベースにアクセスすることが挙げられます。これは、「Security Tips and Tricks」ガイドの Security Identity Customization セクションで説明されています。jakarta.enterprise.context.ContextNotActiveException
で認証または認可が失敗した場合、プロアクティブ認証の無効化が最善の解決策となることがよくあります。また、ユーザーは @ActivateRequestContext
アノテーションなどを使用して CDI リクエストコンテキスト を有効化することもできます。ただし、一部の CDI Bean はまだ使用可能な状態でない場合があります。
この解決策の例外として、アプリケーションエンドポイントが 設定を使用した認可 で保護されている場合があります。詳細は、「Web エンドポイントの認可」ガイドの HttpSecurityPolicy への RequestScoped Bean の注入 セクションを参照してください。