5.5. アプリケーションの作成
まず、/{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 OIDC provider. */ @Inject @IdToken JsonWebToken idToken; /** * Injection point for the Access Token issued by the OIDC provider. */ @Inject JsonWebToken accessToken; /** * Returns the ID Token info. * This endpoint exists only for demonstration purposes. * Do 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. * Do 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(); } }
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 OIDC provider.
*/
@Inject
@IdToken
JsonWebToken idToken;
/**
* Injection point for the Access Token issued by the OIDC provider.
*/
@Inject
JsonWebToken accessToken;
/**
* Returns the ID Token info.
* This endpoint exists only for demonstration purposes.
* Do 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.
* Do 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.quarkus.oidc.runtime.OidcUtils; 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 = OidcTenantConfig .authServerUrl(keycloakUrl + "/realms/tenant-a") .tenantId("tenant-a") .clientId("multi-tenant-client") .credentials("secret") .applicationType(ApplicationType.HYBRID) .build(); return Uni.createFrom().item(config); } else { // resolve to default tenant config return Uni.createFrom().nullItem(); } } }
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.quarkus.oidc.runtime.OidcUtils;
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 = OidcTenantConfig
.authServerUrl(keycloakUrl + "/realms/tenant-a")
.tenantId("tenant-a")
.clientId("multi-tenant-client")
.credentials("secret")
.applicationType(ApplicationType.HYBRID)
.build();
return Uni.createFrom().item(config);
} else {
// resolve to default tenant config
return Uni.createFrom().nullItem();
}
}
}
前述の実装では、テナントはリクエストパスから解決されます。テナントを推測できない場合は、デフォルトのテナント設定を使用する必要があることを示す null
が返されます。
tenant-a
アプリケーションタイプは hybrid
です。提供されている場合、HTTP ベアラートークンを受け入れることができます。それ以外の場合は、認証が必要なときに認可コードフローを開始します。