SAML 提供多租戶,這表示可以使用多個 Keycloak 領域保護單一目標應用程式 (WAR)。這些領域可以位於相同的 Keycloak 執行個體或不同的執行個體上。
若要執行此操作,應用程式必須有多個 keycloak-saml.xml
轉接器設定檔。
雖然您可以有多個 WAR 執行個體,這些執行個體具有部署到不同內容路徑的不同轉接器設定檔,但這可能不方便,而且您也可能想要根據內容路徑以外的其他內容來選取領域。
Keycloak 可以使用自訂組態解析器,因此您可以選擇每個請求使用哪個轉接器組態。在 SAML 中,組態只在登入處理中才有趣;一旦使用者登入,工作階段就會經過驗證,而且傳回的 keycloak-saml.xml
是否不同並不重要。因此,為相同的工作階段傳回相同的組態是正確的方法。
若要達到此目的,請建立 org.keycloak.adapters.saml.SamlConfigResolver
的實作。下列範例使用 Host
標頭來找出適當的組態,並從應用程式的 Java 類別路徑載入該組態及相關聯的元素
package example;
import java.io.InputStream;
import org.keycloak.adapters.saml.SamlConfigResolver;
import org.keycloak.adapters.saml.SamlDeployment;
import org.keycloak.adapters.saml.config.parsers.DeploymentBuilder;
import org.keycloak.adapters.saml.config.parsers.ResourceLoader;
import org.keycloak.adapters.spi.HttpFacade;
import org.keycloak.saml.common.exceptions.ParsingException;
public class SamlMultiTenantResolver implements SamlConfigResolver {
@Override
public SamlDeployment resolve(HttpFacade.Request request) {
String host = request.getHeader("Host");
String realm = null;
if (host.contains("tenant1")) {
realm = "tenant1";
} else if (host.contains("tenant2")) {
realm = "tenant2";
} else {
throw new IllegalStateException("Not able to guess the keycloak-saml.xml to load");
}
InputStream is = getClass().getResourceAsStream("/" + realm + "-keycloak-saml.xml");
if (is == null) {
throw new IllegalStateException("Not able to find the file /" + realm + "-keycloak-saml.xml");
}
ResourceLoader loader = new ResourceLoader() {
@Override
public InputStream getResourceAsStream(String path) {
return getClass().getResourceAsStream(path);
}
};
try {
return new DeploymentBuilder().build(is, loader);
} catch (ParsingException e) {
throw new IllegalStateException("Cannot load SAML deployment", e);
}
}
}
您也必須設定要在您的 web.xml
中使用哪個 SamlConfigResolver
實作,並使用 keycloak.config.resolver
內容參數
<web-app>
...
<context-param>
<param-name>keycloak.config.resolver</param-name>
<param-value>example.SamlMultiTenantResolver</param-value>
</context-param>
</web-app>