OpenID Connect (OIDC) マルチテナンシーの使用
このガイドでは、OpenID Connect (OIDC) アプリケーションがマルチテナンシーをサポートして、単一のアプリケーションから複数のテナントにサービスを提供する方法を説明します。テナントは、同じ OpenID プロバイダー内の個別のレルムまたはセキュリティードメイン、あるいは個別の OpenID プロバイダーです。
同じアプリケーション (例: SaaS) から複数の顧客にサービスを提供する場合、各顧客はテナントです。アプリケーションに対してマルチテナンシーサポートを有効にすることで、Keycloak や Google などのさまざまな OpenID プロバイダーに対する認証であっても、テナントごとに異なる認証ポリシーをサポートできます。
Please read the OIDC Bearer token authentication guide if you need to authorize a tenant using Bearer Token Authorization.
If you need to authenticate and authorize a tenant using OpenID Connect Authorization Code Flow, read the OIDC code flow mechanism for protecting web applications guide.
また、 OIDC設定プロパティ のリファレンスガイドもご参照ください。
前提条件
このガイドを完成させるには、以下が必要です:
-
約15分
-
IDE
-
JDK 11+ がインストールされ、
JAVA_HOME
が適切に設定されていること -
Apache Maven 3.9.3
-
動作するコンテナランタイム(Docker, Podman)
-
使用したい場合は、 Quarkus CLI
-
ネイティブ実行可能ファイルをビルドしたい場合、MandrelまたはGraalVM(あるいはネイティブなコンテナビルドを使用する場合はDocker)をインストールし、 適切に設定していること
アーキテクチャ
この例では、2つのリソースメソッドをサポートする非常にシンプルなアプリケーションを構築します:
-
/{tenant}
OpenID Providerが発行するIDトークンから取得した、認証されたユーザと現在のテナントに関する情報を返すリソースです。
-
/{tenant}
/bearer
OpenID Providerが発行するアクセストークンから取得した、認証されたユーザと現在のテナントに関する情報を返すリソースです。
ソリューション
次の章で紹介する手順に沿って、ステップを踏んでアプリを作成することをお勧めします。ただし、完成した例にそのまま進んでも構いません。
Git リポジトリーのクローンを作成: git clone https://github.com/quarkusio/quarkus-quickstarts.git
、または アーカイブ をダウンロードします。
The solution is located in the security-openid-connect-multi-tenancy-quickstart
directory.
Maven プロジェクトの作成
まず、新しいプロジェクトが必要です。以下のコマンドで新規プロジェクトを作成します:
Windowsユーザーの場合:
-
If using cmd, (don’t use backward slash
\
and put everything on the same line) -
If using Powershell, wrap
-D
parameters in double quotes e.g."-DprojectArtifactId=security-openid-connect-multi-tenancy-quickstart"
すでにQuarkusプロジェクトが設定されている場合は、プロジェクトのベースディレクトリーで以下のコマンドを実行することで、プロジェクトに oidc
エクステンションを追加することができます:
quarkus extension add 'oidc'
./mvnw quarkus:add-extension -Dextensions='oidc'
./gradlew addExtension --extensions='oidc'
これにより、ビルドファイルに以下が追加されます:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-oidc</artifactId>
</dependency>
implementation("io.quarkus:quarkus-oidc")
アプリケーションの記述
まず、 /{tenant}
のエンドポイントを実装することから始めましょう。以下のソースコードからわかるように、これは通常の Jakarta REST リソースです:
package org.acme.quickstart.oidc;
import jakarta.inject.Inject;
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import org.eclipse.microprofile.jwt.JsonWebToken;
import io.quarkus.oidc.IdToken;
@Path("/{tenant}")
public class HomeResource {
/**
* Injection point for the ID Token issued by the OpenID Connect Provider
*/
@Inject
@IdToken
JsonWebToken idToken;
/**
* Injection point for the Access Token issued by the OpenID Connect Provider
*/
@Inject
JsonWebToken accessToken;
/**
* Returns the ID Token info. This endpoint exists only for demonstration purposes, you should not
* expose this token in a real application.
*
* @return ID Token info
*/
@GET
@Produces("text/html")
public String getIdTokenInfo() {
StringBuilder response = new StringBuilder().append("<html>")
.append("<body>");
response.append("<h2>Welcome, ").append(this.idToken.getClaim("email").toString()).append("</h2>\n");
response.append("<h3>You are accessing the application within tenant <b>").append(idToken.getIssuer()).append(" boundaries</b></h3>");
return response.append("</body>").append("</html>").toString();
}
/**
* Returns the Access Token info. This endpoint exists only for demonstration purposes, you should not
* expose this token in a real application.
*
* @return Access Token info
*/
@GET
@Produces("text/html")
@Path("bearer")
public String getAccessTokenInfo() {
StringBuilder response = new StringBuilder().append("<html>")
.append("<body>");
response.append("<h2>Welcome, ").append(this.accessToken.getClaim("email").toString()).append("</h2>\n");
response.append("<h3>You are accessing the application within tenant <b>").append(accessToken.getIssuer()).append(" boundaries</b></h3>");
return response.append("</body>").append("</html>").toString();
}
}
受信リクエストからテナントを解決し、application.propertiesで特定の quarkus-oidc
テナント設定にマッピングするためには、テナント設定を動的に解決するために使用できる io.quarkus.oidc.TenantConfigResolver
インターフェイスの実装を作成する必要があります:
package org.acme.quickstart.oidc;
import jakarta.enterprise.context.ApplicationScoped;
import org.eclipse.microprofile.config.ConfigProvider;
import io.quarkus.oidc.OidcRequestContext;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.OidcTenantConfig.ApplicationType;
import io.quarkus.oidc.TenantConfigResolver;
import io.smallrye.mutiny.Uni;
import io.vertx.ext.web.RoutingContext;
@ApplicationScoped
public class CustomTenantResolver implements TenantConfigResolver {
@Override
public Uni<OidcTenantConfig> resolve(RoutingContext context, OidcRequestContext<OidcTenantConfig> requestContext) {
String path = context.request().path();
if (path.startsWith("/tenant-a")) {
String keycloakUrl = ConfigProvider.getConfig().getValue("keycloak.url", String.class);
OidcTenantConfig config = new OidcTenantConfig();
config.setTenantId("tenant-a");
config.setAuthServerUrl(keycloakUrl + "/realms/tenant-a");
config.setClientId("multi-tenant-client");
config.getCredentials().setSecret("secret");
config.setApplicationType(ApplicationType.HYBRID);
return Uni.createFrom().item(config);
} else {
// resolve to default tenant config
return Uni.createFrom().nullItem();
}
}
}
上記の実装から、テナントはリクエストパスから解決されるため、テナントを推測できなかった場合は、デフォルトのテナント設定を使用する必要があることを示すために null が返されます。
tenant-a
アプリケーションタイプは hybrid
であることに注意してください。HTTPベアラートークンが提供された場合はそれを受け入れることができますが、そうでない場合は認証が必要なときに認可コードフローが開始されます。
アプリケーションの設定
# Default Tenant Configuration
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=multi-tenant-client
quarkus.oidc.application-type=web-app
# Tenant A Configuration is created dynamically in CustomTenantConfigResolver
# HTTP Security Configuration
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
The first configuration is the default tenant configuration that should be used when the tenant can not be inferred from the request. Note that a %prod
profile prefix is used with quarkus.oidc.auth-server-url
- it is done to support testing a multi-tenant application with Dev Services For Keycloak
. This configuration is using a Keycloak instance to authenticate users.
2つ目の設定は TenantConfigResolver
によって提供されます。これは、受信リクエストがテナント tenant-a
にマッピングされるときに使用される設定です。
どちらの設定でも、異なる realms
を使用しばら、同じ Keycloak サーバーインスタンスにマップされることに注意してください。
または、 application.properties
で直接テナント tenant-a
を設定することもできます:
# Default Tenant Configuration
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=multi-tenant-client
quarkus.oidc.application-type=web-app
# Tenant A Configuration
quarkus.oidc.tenant-a.auth-server-url=http://localhost:8180/realms/tenant-a
quarkus.oidc.tenant-a.client-id=multi-tenant-client
quarkus.oidc.tenant-a.application-type=web-app
# HTTP Security Configuration
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
そして、カスタム TenantConfigResolver
を使って解決します:
package org.acme.quickstart.oidc;
import jakarta.enterprise.context.ApplicationScoped;
import io.quarkus.oidc.TenantResolver;
import io.vertx.ext.web.RoutingContext;
@ApplicationScoped
public class CustomTenantResolver implements TenantResolver {
@Override
public String resolve(RoutingContext context) {
String path = context.request().path();
String[] parts = path.split("/");
if (parts.length == 0) {
// resolve to default tenant configuration
return null;
}
return parts[1];
}
}
設定ファイルで複数のテナントを定義できます。TenantResolver
実装からテナントを解決するときに適切にマップできるように、それらに一意のエイリアスがあることを確認してください。
しかし、静的なテナント解決( application.properties
でテナントを設定し、 TenantResolver
で解決する)を使用すると、 Dev Services for Keycloak
でエンドポイントをテストすることができません。 Dev Services for Keycloak
は、リクエストが個々のテナントにどのようにマッピングされるかを知らないため、テナント固有の quarkus.oidc.<tenant-id>.auth-server-url
値を動的に提供できず、したがって %prod
プレフィックスを使用して application.properties
のテナントに固有の URL を使用するとテストや開発モードで動作しません。
現在のテナントが OIDC の
In fact, this is how Quarkus OIDC resolves static custom tenants itself if no custom 同様の手法は、 |
If you also use Hibernate ORM multitenancy or MongoDB with Panache multitenancy and both tenant IDs are the same and must be extracted from the Vert.x
|
Keycloak サーバーの起動と設定
Keycloak サーバーを起動するにはDockerを使用し、以下のコマンドを実行するだけです。
docker run --name keycloak -e KEYCLOAK_ADMIN=admin -e KEYCLOAK_ADMIN_PASSWORD=admin -p 8180:8080 quay.io/keycloak/keycloak:{keycloak.version} start-dev
ここで、keycloak.version
は 17.0.0
以上に設定する必要があります。
localhost:8180 で Keycloak サーバーにアクセスできるはずです。
Keycloak 管理コンソールにアクセスするには、 admin
ユーザーとしてログインしてください。ユーザー名は admin
、パスワードは admin
です。
さて、以下の手順に従って、2つのテナントのためのレルムをインポートします。
-
Import the default-tenant-realm.json to create the default realm
-
Import the tenant-a-realm.json to create the realm for the tenant
tenant-a
.
詳細は、 新規レルムの作成 方法に関する Keycloak ドキュメントを参照してください。
アプリケーションの実行と使用
デベロッパーモードでの実行
マイクロサービスをdevモードで実行する場合、次を実行して下さい:
quarkus dev
./mvnw quarkus:dev
./gradlew --console=plain quarkusDev
JVM モードでの実行
「開発モード」で遊び終わったら、標準のJavaアプリケーションとして実行することができます。
まずコンパイルします。
quarkus build
./mvnw install
./gradlew build
次に、以下を実行してください。
java -jar target/quarkus-app/quarkus-run.jar
ネイティブモードでの実行
同じデモをネイティブコードにコンパイルすることができます。
これは、生成されたバイナリーにランタイム技術が含まれており、最小限のリソースオーバーヘッドで実行できるように最適化されているため、本番環境にJVMをインストールする必要がないことを意味します。
コンパイルには少し時間がかかるので、このステップはデフォルトで無効になっています。ネイティブビルドを有効にして再度ビルドしてみましょう。
quarkus build --native
./mvnw install -Dnative
./gradlew build -Dquarkus.package.type=native
コーヒーを飲み終わると、このバイナリーは以下のように直接実行出来るようになります:
./target/security-openid-connect-multi-tenancy-quickstart-runner
アプリケーションのテスト
Dev Services for Keycloakの使用
Keycloakに対する統合テストには、 Dev Services for Keycloak の使用を推奨します。 Dev Services for Keycloak
はテストコンテナを起動し初期化します。設定されたレルムをインポートし、このクイックスタートで使用される CustomTenantResolver
のベース Keycloak URL を設定して、レルム固有の URL を計算します。
まず、以下の依存関係を追加する必要があります:
<dependency>
<groupId>io.quarkus</groupId>
<artifactId>quarkus-test-keycloak-server</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>io.rest-assured</groupId>
<artifactId>rest-assured</artifactId>
<scope>test</scope>
</dependency>
<dependency>
<groupId>net.sourceforge.htmlunit</groupId>
<artifactId>htmlunit</artifactId>
<scope>test</scope>
</dependency>
testImplementation("io.quarkus:quarkus-test-keycloak-server")
testImplementation("io.rest-assured:rest-assured")
testImplementation("net.sourceforge.htmlunit:htmlunit")
quarkus-test-keycloak-server
は、レルム固有のアクセストークンを取得するためのユーティリティクラス io.quarkus.test.keycloak.client.KeycloakTestClient
を提供し、 RestAssured
と共にベアラアクセストークンを期待する /{tenant}/bearer
エンドポイントのテストに使用できます。HtmlUnit
は /{tenant}
エンドポイントと認可コードフローのテストに使用します。
次に、必要なレルムを設定します:
# Default Tenant Configuration
%prod.quarkus.oidc.auth-server-url=http://localhost:8180/realms/quarkus
quarkus.oidc.client-id=multi-tenant-client
quarkus.oidc.application-type=web-app
# Tenant A Configuration is created dynamically in CustomTenantConfigResolver
# HTTP Security Configuration
quarkus.http.auth.permission.authenticated.paths=/*
quarkus.http.auth.permission.authenticated.policy=authenticated
quarkus.keycloak.devservices.realm-path=default-tenant-realm.json,tenant-a-realm.json
最後に、JVM モードで実行されるテストを作成します。
package org.acme.quickstart.oidc;
import static org.hamcrest.Matchers.containsString;
import static org.junit.jupiter.api.Assertions.assertEquals;
import static org.junit.jupiter.api.Assertions.assertTrue;
import java.io.IOException;
import org.junit.jupiter.api.Test;
import com.gargoylesoftware.htmlunit.SilentCssErrorHandler;
import com.gargoylesoftware.htmlunit.WebClient;
import com.gargoylesoftware.htmlunit.html.HtmlForm;
import com.gargoylesoftware.htmlunit.html.HtmlPage;
import io.quarkus.test.junit.QuarkusTest;
import io.quarkus.test.keycloak.client.KeycloakTestClient;
import io.restassured.RestAssured;
@QuarkusTest
public class CodeFlowTest {
KeycloakTestClient keycloakClient = new KeycloakTestClient();
@Test
public void testLogInDefaultTenant() throws IOException {
try (final WebClient webClient = createWebClient()) {
HtmlPage page = webClient.getPage("http://localhost:8081/default");
assertEquals("Sign in to quarkus", page.getTitleText());
HtmlForm loginForm = page.getForms().get(0);
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
assertTrue(page.asText().contains("tenant"));
}
}
@Test
public void testLogInTenantAWebApp() throws IOException {
try (final WebClient webClient = createWebClient()) {
HtmlPage page = webClient.getPage("http://localhost:8081/tenant-a");
assertEquals("Sign in to tenant-a", page.getTitleText());
HtmlForm loginForm = page.getForms().get(0);
loginForm.getInputByName("username").setValueAttribute("alice");
loginForm.getInputByName("password").setValueAttribute("alice");
page = loginForm.getInputByName("login").click();
assertTrue(page.asText().contains("alice@tenant-a.org"));
}
}
@Test
public void testLogInTenantABearerToken() throws IOException {
RestAssured.given().auth().oauth2(getAccessToken()).when()
.get("/tenant-a/bearer").then().body(containsString("alice@tenant-a.org"));
}
private String getAccessToken() {
return keycloakClient.getRealmAccessToken("tenant-a", "alice", "alice", "multi-tenant-client", "secret");
}
private WebClient createWebClient() {
WebClient webClient = new WebClient();
webClient.setCssErrorHandler(new SilentCssErrorHandler());
return webClient;
}
}
ネイティブモードの場合:
package org.acme.quickstart.oidc;
import io.quarkus.test.junit.QuarkusIntegrationTest;
@QuarkusIntegrationTest
public class CodeFlowIT extends CodeFlowTest {
}
初期化および設定方法の詳細については、Dev Services for Keycloak を参照してください。
ブラウザの使用
テストするには、ブラウザを開いて以下のURLにアクセスする必要があります。
すべてが期待どおりに機能している場合は、認証のために Keycloak サーバーにリダイレクトする必要があります。リクエストされたパスは、設定ファイルにマップされていない default
テナントを定義していることに注意してください。この場合、デフォルトの設定が使用されます。
アプリケーションを認証するためには、Keycloakのログインページで以下の認証情報を入力する必要があります。
-
Username: alice
-
Password: alice
Login
ボタンをクリックすると、アプリケーションにリダイレクトされます。
次の URL でアプリケーションにアクセスを試みます。
Keycloak のログインページに再度リダイレクトされます。ただし、ここでは別の realm
を使用して認証します。
どちらの場合も、ユーザーが正常に認証されると、ランディングページにユーザーの名前と電子メールが表示されます。ユーザー alice
は両方のテナントに存在しますが、アプリケーションにおいて、それらは異なるレルム/テナントに属する別個のユーザーです。
Static tenant configuration resolution
When you set multiple tenant configurations in the application.properties
file, you only need to specify how the tenant identifier gets resolved. To configure the resolution of the tenant identifier, use one of the following options:
Default resolution
The default resolution for a tenant identifier is convention based, whereby the authentication request must include the tenant identifier in the last segment of the request path.
The following application.properties
example shows how you can configure two tenants named google
and github
:
# Tenant 'google' configuration
quarkus.oidc.google.provider=google
quarkus.oidc.google.client-id=${google-client-id}
quarkus.oidc.google.credentials.secret=${google-client-secret}
quarkus.oidc.google.authentication.redirect-path=/signed-in
# Tenant 'github' configuration
quarkus.oidc.github.provider=google
quarkus.oidc.github.client-id=${github-client-id}
quarkus.oidc.github.credentials.secret=${github-client-secret}
quarkus.oidc.github.authentication.redirect-path=/signed-in
In this example, both tenants configure OIDC web-app
applications to use an authorization code flow to authenticate users and also require session cookies to get generated after the authentication has taken place. After either Google or GitHub authenticates the current user, the user gets returned to the /signed-in
area for authenticated users, for example, a secured resource path on the JAX-RS endpoint.
Finally, to complete the default tenant resolution, set the following configuration property:
quarkus.http.auth.permission.login.paths=/google,/github
quarkus.http.auth.permission.login.policy=authenticated
If the endpoint is running on http://localhost:8080
, you can also provide UI options for users to log in to either http://localhost:8080/google
or http://localhost:8080/github
, without having to add specific`/google` or /github
JAX-RS resource paths. Tenant identifiers are also recorded in the session cookie names after the authentication is completed. Therefore, authenticated users can access the secured application area without requiring either the google
or github
path values to be included in the secured URL.
Default resolution can also work for Bearer token authentication but it might be less practical in this case because a tenant identifier will always need to be set as the last path segment value.
Resolve with TenantResolver
The following application.properties
example shows how you can resolve the tenant identifier of two tenants named a
and b
by using the TenantResolver
method:
# Tenant 'a' configuration
quarkus.oidc.a.auth-server-url=http://localhost:8180/realms/quarkus-a
quarkus.oidc.a.client-id=client-a
quarkus.oidc.a.credentials.secret=client-a-secret
# Tenant 'b' configuration
quarkus.oidc.b.auth-server-url=http://localhost:8180/realms/quarkus-b
quarkus.oidc.b.client-id=client-b
quarkus.oidc.b.credentials.secret=client-b-secret
You can return the tenant ID of either a
or b
from quarkus.oidc.TenantResolver
:
import quarkus.oidc.TenantResolver;
public class CustomTenantResolver implements TenantResolver {
@Override
public String resolve(RoutingContext context) {
String path = context.request().path();
if (path.endsWith("a")) {
return "a";
} else if (path.endsWith("b")) {
return "b";
} else {
// default tenant
return null;
}
}
}
In this example, the value of the last request path segment is a tenant ID, but if required, you can implement a more complex tenant identifier resolution logic.
Resolve with annotations
You can use the io.quarkus.oidc.Tenant
annotation for resolving the tenant identifiers as an alternative to using io.quarkus.oidc.TenantResolver
.
Proactive HTTP authentication must be disabled ( |
Assuming your application supports two OIDC tenants (hr
, and default), all resource methods and classes carrying @Tenant("hr")
will be authenticated using the OIDC provider configured by quarkus.oidc.hr.auth-server-url
, while all other classes and methods will still be authenticated using the default OIDC provider.
import jakarta.ws.rs.GET;
import jakarta.ws.rs.Path;
import jakarta.ws.rs.Produces;
import jakarta.ws.rs.core.MediaType;
import io.quarkus.oidc.Tenant;
import io.quarkus.security.Authenticated;
@Authenticated
@Path("/api/hello")
public class HelloResource {
@Tenant("hr") (1)
@GET
@Produces(MediaType.TEXT_PLAIN)
public String sayHello() {
return "Hello!";
}
}
1 | The io.quarkus.oidc.Tenant annotation must be placed either on resource class or resource method. |
Dynamic tenant configuration resolution
サポートしたいさまざまなテナントに対して、より動的な設定が必要で、設定ファイルに複数のエントリーを入れたくない場合は、 io.quarkus.oidc.TenantConfigResolver
が利用出来ます。
このインターフェイスを使用すると、実行時にテナント設定を動的に作成することができます。
package io.quarkus.it.keycloak;
import jakarta.enterprise.context.ApplicationScoped;
import java.util.function.Supplier;
import io.smallrye.mutiny.Uni;
import io.quarkus.oidc.OidcRequestContext;
import io.quarkus.oidc.OidcTenantConfig;
import io.quarkus.oidc.TenantConfigResolver;
import io.vertx.ext.web.RoutingContext;
@ApplicationScoped
public class CustomTenantConfigResolver implements TenantConfigResolver {
@Override
public Uni<OidcTenantConfig> resolve(RoutingContext context, OidcRequestContext<OidcTenantConfig> requestContext) {
String path = context.request().path();
String[] parts = path.split("/");
if (parts.length == 0) {
// resolve to default tenant configuration
return null;
}
if ("tenant-c".equals(parts[1])) {
// Do 'return requestContext.runBlocking(createTenantConfig());'
// if a blocking call is required to create a tenant config
return Uni.createFromItem(createTenantConfig());
}
// resolve to default tenant configuration
return null;
}
private Supplier<OidcTenantConfig> createTenantConfig() {
final OidcTenantConfig config = new OidcTenantConfig();
config.setTenantId("tenant-c");
config.setAuthServerUrl("http://localhost:8180/realms/tenant-c");
config.setClientId("multi-tenant-client");
OidcTenantConfig.Credentials credentials = new OidcTenantConfig.Credentials();
credentials.setSecret("my-secret");
config.setCredentials(credentials);
// any other setting support by the quarkus-oidc extension
return () -> config;
}
}
このメソッドから返される OidcTenantConfig
は、application.properties
から oidc
名前空間設定を解析するために使用されるものと同じです。quarkus-oidc
エクステンションでサポートされている任意の設定を使用してデータを入力できます。
Tenant resolution for OIDC web-app
applications
The simplest option for resolving OIDC web-app
application configuration is to follow the steps described in the Default resolution section.
Try one of the options suggested below if the default resolution strategy does not work for your application setup.
service
と web-app
の両方の OIDC アプリケーションの現在の HTTP リクエストを保護するために使用する必要があるテナント設定を選択する際には、次のようないくつかのオプションを使用できます:
-
URL パスを確認します。たとえば、"/service" パスには
tenant-service
設定を使用する必要がありますが、 "/management" パスにはtenant-manage
設定を使用する必要があります -
たとえば、URL パスが常に '/service' である HTTP ヘッダーを確認します。"Realm: service" や "Realm: management" などのヘッダーは、
tenant-service
設定やtenant-manage
設定のいずれかを選択する場合に役立ちます。 -
URL クエリーパラメーターを確認します。ヘッダーを使用してテナント設定を選択するのと同じように機能します
これらのオプションはすべて、OIDC service
アプリケーションのカスタムの TenantResolver
実装や TenantConfigResolver
実装を使用して簡単に実装できます。
ただし、OIDC web-app
アプリケーションのコード認証フローを完了するために HTTP リダイレクトが必要なため、次の理由により、このリダイレクトリクエストの前後に同じテナント設定を選択するためにカスタム HTTP Cookie が必要になる場合があります。
-
単一のリダイレクト URL が OIDC プロバイダーに登録されている場合、リダイレクトリクエスト後の URL パスは同じではない可能性があります。元のリクエストパスは復元できますが、それはテナント設定が解決された後です。
-
元のリクエスト中に使用された HTTP ヘッダーは、リダイレクト後に使用できなくなります。
-
カスタム URL クエリーパラメーターは、リダイレクト後、テナント設定が解決された後に復元されます。
リダイレクトの前後に web-app
アプリケーションのテナント設定を解決するための情報を確実に利用できるようにするための 1 つのオプションは、Cookie を使用することです。以下はその例です。
package org.acme.quickstart.oidc;
import java.util.List;
import jakarta.enterprise.context.ApplicationScoped;
import io.quarkus.oidc.TenantResolver;
import io.vertx.core.http.Cookie;
import io.vertx.ext.web.RoutingContext;
@ApplicationScoped
public class CustomTenantResolver implements TenantResolver {
@Override
public String resolve(RoutingContext context) {
List<String> tenantIdQuery = context.queryParam("tenantId");
if (!tenantIdQuery.isEmpty()) {
String tenantId = tenantIdQuery.get(0);
context.addCookie(Cookie.cookie("tenant", tenantId));
return tenantId;
} else if (context.cookieMap().containsKey("tenant")) {
return context.getCookie("tenant").getValue();
}
return null;
}
}
テナント設定を無効にする
カスタムの TenantResolver
および TenantConfigResolver
の実装では、現在のリクエストからテナントを推測できず、デフォルトのテナント設定へのフォールバックが必要な場合は null
を返すことがあります。
If you expect that the custom resolvers will always infer a tenant then you do not need to configure the default tenant resolution.
-
To disable the default tenant configuration, set
quarkus.oidc.tenant-enabled=false
.
The default tenant configuration is automatically disabled when |
テナント固有の設定を無効にすることもできます。例: quarkus.oidc.tenant-a.tenant-enabled=false