使用 Keycloak 的自定義協議映射器
一、簡介
Keycloak 是一種開源身份和訪問管理 (IAM) 解決方案,專注於現代應用程序和服務。當用戶通過 Keycloak 進行身份驗證時,服務器頒發的令牌包含有關已通過身份驗證的用戶和令牌頒發給的客戶端的重要信息。
Keycloak的token包含一些默認屬性,比如iss
(發行者)、 exp
(過期時間)、 sub
(主題)、 aud
(受眾)。但很多時候,這些還不夠,我們可能需要向令牌添加一些額外的信息。在這種情況下,我們使用協議映射器。
在本教程中,我們將展示如何將自定義協議映射器添加到 Keycloak 授權服務器。
2.協議映射器
Keycloak 令牌只是一個包含一組聲明的 JSON 對象,通常經過數字簽名。讓我們看看令牌的有效負載及其標準化聲明集合的示例:
{
"exp": 1680679982,
"iat": 1680679682,
"jti": "bebf7b2c-f813-47be-ad63-0ca6323bba19",
"iss": "http://192.168.198.128:8085/auth/realms/baeldung",
"aud": "account",
"sub": "648b0687-c002-441d-b797-0003b30168ed",
"typ": "Bearer",
"azp": "client-app",
"acr": "1",
...
"scope": "email profile",
"clientId": "client-app",
"clientHost": "192.168.198.1",
"email_verified": false,
"preferred_username": "service-account-client-app",
"clientAddress": "192.168.198.1"
}
協議映射器將電子郵件地址等項目映射到身份和訪問令牌中的特定聲明。我們可以通過向客戶端添加協議映射器來自定義具有特定詳細信息的令牌中的聲明。
3.設置Keycloak服務器
在本教程中,我們將使用 Keycloak 獨立版本。我們已經介紹瞭如何設置 Keycloak 服務器,因此我們不會在這裡詳細介紹它是如何完成的。
讓我們向我們的 Keycloak 實例添加一個名為baeldung
的新領域和一個名為client-app
的新客戶端:
除了Client authentication
和Service accounts roles
字段外,我們將保留所有默認值:
Service accounts roles
字段支持為此客戶端授予Client Credentials Grant
。
4.自定義協議映射器實現
現在我們已經設置了 Keycloak 服務器,我們將創建一個自定義協議映射器並在 Keycloak 服務器中配置它。
4.1.依賴關係
我們的自定義協議映射器是創建 JAR 文件的常規 Maven 項目。
讓我們首先在pom.xml
中聲明keycloak-core
、 keycloak-server-spi
、 keycloak-server-spi-private
和keycloak-services
依賴項:
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-core</artifactId>
<scope>provided</scope>
<version>21.0.1</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi</artifactId>
<scope>provided</scope>
<version>21.0.1</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-server-spi-private</artifactId>
<scope>provided</scope>
<version>21.0.1</version>
</dependency>
<dependency>
<groupId>org.keycloak</groupId>
<artifactId>keycloak-services</artifactId>
<scope>provided</scope>
<version>21.0.1</version>
</dependency>
4.2.擴展AbstractOIDCProtocolMapper
類
現在讓我們創建我們的協議映射器。為此,我們擴展了AbstractOIDCProtocolMapper
類並實現了所有抽象方法:
public class CustomProtocolMapper extends AbstractOIDCProtocolMapper implements OIDCAccessTokenMapper,
OIDCIDTokenMapper, UserInfoTokenMapper {
public static final String PROVIDER_ID = "custom-protocol-mapper";
private static final List<ProviderConfigProperty> configProperties = new ArrayList<>();
static {
OIDCAttributeMapperHelper.addTokenClaimNameConfig(configProperties);
OIDCAttributeMapperHelper.addIncludeInTokensConfig(configProperties, CustomProtocolMapper.class);
}
@Override
public String getDisplayCategory() {
return "Token Mapper";
}
@Override
public String getDisplayType() {
return "Custom Token Mapper";
}
@Override
public String getHelpText() {
return "Adds a Baeldung text to the claim";
}
@Override
public List<ProviderConfigProperty> getConfigProperties() {
return configProperties;
}
@Override
public String getId() {
return PROVIDER_ID;
}
@Override
protected void setClaim(<br /> IDToken token,<br /> ProtocolMapperModel mappingModel,
UserSessionModel userSession,<br /> KeycloakSession keycloakSession,
ClientSessionContext clientSessionCtx) {
OIDCAttributeMapperHelper.mapClaim(token, mappingModel, "Baeldung");
}
}
我們為我們的提供商 ID 選擇了“custom-protocol-mapper”
,這是令牌映射器的 ID。我們需要這個 ID 來配置我們的 Keycloak 服務器中的協議映射器。
主要方法是setClaim()
。它將我們的數據添加到令牌中。我們的setClaim()
實現只是將Baeldung
文本添加到令牌中。
getDisplayType()
和getHelpText()
方法用於管理控制台。 getDisplayType()
方法定義了在列出協議映射器時將在管理控制台中顯示的文本。 getHelpText()
方法是我們選擇協議映射器時顯示的工具提示文本。
4.3.匯集一切
我們不能忘記創建服務定義文件並將其添加到我們的項目中。該文件應命名為org.keycloak.protocol.ProtocolMapper
並放置在我們最終 JAR 的META-INF/services
目錄中。此外,該文件的內容是自定義協議映射器實現的完全限定類名:
com.baeldung.auth.provider.mapper.CustomProtocolMapper
目錄結構如下圖所示:
現在,該項目已準備好運行。首先,我們使用 Maven install
命令創建一個 JAR 文件:
mvn clean install
接下來,我們通過將 JAR 文件添加到 Keycloak 的providers
目錄來將其部署到 Keycloak。之後,我們必須重新啟動服務器以使用 JAR 文件中的實現更新服務器的提供程序註冊表:
$ bin/kc.sh start-dev
正如我們在控制台輸出中看到的那樣,Keycloak 註冊了我們的自定義協議映射器:
Updating the configuration and installing your custom providers, if any. Please wait.
2023-04-05 14:55:42,588 WARN [org.keycloak.services] (build-108) KC-SERVICES0047: custom-protocol-mapper (com.baeldung.auth.provider.CustomProtocolMapper) is implementing the internal SPI protocol-mapper.
最後,如果我們轉到 Keycloak 管理控制台提供的Provider info
頁面,我們將看到我們的custom-protocol-mapper
:
現在,我們可以將服務器配置為使用我們的自定義協議映射器。
4.4.配置客戶端
在 Keycloak 中,我們可以使用管理面板添加自定義聲明。為此,我們需要在管理控制台上訪問我們的客戶端。回想一下,我們之前創建了一個客戶端client-app
。之後,我們導航到Client scopes
選項卡:
現在,讓我們點擊client-app-dedicated
並轉到其Add mapper By configuration
來創建一個新的映射:
在這裡,我們需要為自定義映射器輸入Mapper type
。我們將鍵入“ Custom Token Mapper
”,這是我們在CustomProtocolMapper
類中用於getDisplayType()
方法的值:
接下來,我們為映射器Name
並保存。然後,當我們回到client-app-dedicated
時,我們會在列表中看到新的映射:
現在,我們準備測試我們的協議映射器。
5. 測試
讓我們使用Client Credential
授權類型為客戶端獲取訪問令牌:
curl --location --request POST 'http://server-ip:server-port/auth/realms/baeldung/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'client_id=client-app' \
--data-urlencode 'client_secret=<client-secret>' \
--data-urlencode 'grant_type=client_credentials'
如果我們獲得訪問令牌並使用jwt.io
對其進行解碼,我們會在令牌的主體中找到test
聲明:
{
"exp": 1680679982,
"iat": 1680679682,
...
"email_verified": false,
"test": "Baeldung",
"preferred_username": "service-account-client-app",
"clientAddress": "192.168.198.1"
}
如我們所見, test
聲明的值為Baeldung
。
六,結論
在本文中,我們在 Keycloak 服務器中實現了一個自定義協議映射器。通常,令牌是一組屬性或聲明。協議映射器將提供向令牌添加自定義聲明的選項。
GitHub 上提供了本文所示代碼的工作版本。