Ich habe versucht, mit Keycloak mehrere Mandanten zu realisieren, um Mikrodienste in mehreren Projekten zu verwenden.
Wenn man sich das Originalhandbuch ansieht, scheint es, dass dies mit der Methode resolve () der KeycloakConfigResolver-Schnittstelle möglich ist. Ich möchte jedoch, dass Sie keine Keycloak-Konfigurationen für mehrere Projekte als Json-Dateien vorbereiten. Weitere Untersuchungen haben ergeben, dass Keycloak-Konfigurationen mit AdapterConfig als Argument dynamisch generiert werden können. Da auth_server_url und resource gemeinsam sind, können Sie mehrere Mandanten realisieren, indem Sie in application.yml die im Anforderungsheader eingebettete Projekt-ID auf den Realm-Namen von Keycloak setzen. Ich dachte jedoch, dass das Generieren einer Keycloak-Konfiguration für jede Anforderung ein Leistungsproblem darstellen würde, und entschied mich daher, sie für eine begrenzte Zeit mit Guavas Cache Builder zwischenzuspeichern. ..
RequestBasedKeycloakConfigResolver.java
import com.google.common.cache.CacheBuilder;
import com.google.common.cache.CacheLoader;
import com.google.common.cache.LoadingCache;
import java.util.concurrent.ExecutionException;
import java.util.concurrent.TimeUnit;
import org.keycloak.adapters.KeycloakConfigResolver;
import org.keycloak.adapters.KeycloakDeployment;
import org.keycloak.adapters.KeycloakDeploymentBuilder;
import org.keycloak.adapters.OIDCHttpFacade;
import org.keycloak.representations.adapters.config.AdapterConfig;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
public class RequestBasedKeycloakConfigResolver implements KeycloakConfigResolver {
private final Logger logger = LoggerFactory.getLogger(getClass());
private final LoadingCache<String, KeycloakDeployment> keycloakDeploymentCache;
public RequestBasedKeycloakConfigResolver() {
keycloakDeploymentCache = CacheBuilder
.newBuilder()
.refreshAfterWrite(10, TimeUnit.MINUTES)
.build(
new CacheLoader<String, KeycloakDeployment>(){
@Override
public KeycloakDeployment load(String realm) throws Exception {
return loadKeycloakDeployment(realm);
}
}
);
}
@Value("${keycloak.auth-server-url}")
private String authServerUrl;
@Value("${keycloak.resource}")
private String resource;
@Override
public KeycloakDeployment resolve(OIDCHttpFacade.Request request) {
String realm = request.getHeader("project-id");
try {
return keycloakDeploymentCache.get(realm);
} catch (ExecutionException ex) {
logger.error(ex.getMessage());
return loadKeycloakDeployment(realm);
}
}
private KeycloakDeployment loadKeycloakDeployment(String realm) {
AdapterConfig cfg = new AdapterConfig();
cfg.setRealm(realm);
cfg.setAuthServerUrl(authServerUrl);
cfg.setResource(resource);
return KeycloakDeploymentBuilder.build(cfg);
}
}
Da Keycloak die Authentifizierungsmethode usw. für jeden Bereich definieren kann, war es möglich, mehrere Projekte zu unterstützen, indem der Bereichsname in den Anforderungsheader eingebettet und der Bereich für jede Anforderung mit KeycloakConfigResolver gewechselt wurde. Das Ändern der Keycloak-Sicherheitseinstellungen für jede Anforderung war ein Leistungsproblem, daher habe ich beschlossen, sie vorerst 10 Minuten lang in einem zeitlich begrenzten Cache zu speichern.