1. 概述
Keycloak 是我們 Web 或移動應用程序的用户授權服務器。
它提供了一些默認屬性,例如名字、姓氏和電子郵件,用於存儲任何給定用户的屬性。 但在許多情況下,這些屬性可能不足,我們需要為我們的應用程序添加一些特定的用户屬性。
在本教程中,我們將學習如何將自定義用户屬性添加到 Keycloak 授權服務器,並在基於 Spring 的後端中訪問它們。
首先,我們將針對獨立的 Keycloak 服務器進行演示,然後針對嵌入式 Keycloak 服務器進行演示。
2. 獨立服務器
2.1. 添加自定義用户屬性
首先,請前往 Keycloak 的管理控制枱。為此,我們需要從 Keycloak 分發的 bin 文件夾中運行該命令啓動服務器:
kc.bat start-dev然後我們需要前往 管理控制枱,並輸入 initial1/zaq1!QAZ 憑據。
接下來,我們點擊“用户”選項卡下的 用户。
在這裏我們可以看到我們之前添加的用户:user1。
現在,我們點擊其 ID 並前往“屬性”選項卡,以添加一個新的屬性,DOB 表示出生日期:
點擊“保存”後,自定義屬性將被添加到用户的資料中。
接下來,我們需要為該屬性創建一個映射,作為自定義聲明,以便在用户令牌的 JSON 負載中可用。
為此,我們需要前往應用程序客户端在管理控制枱中的設置。 之前我們創建的客户端是 login-app:
現在,點擊它,然後點擊“客户端範圍”選項卡。 在“客户端範圍”頁面點擊 login-app-dedicated 鏈接並前往其“映射器”選項卡。 現在點擊“配置新的映射器”並選擇“用户屬性”以創建新的映射:
設置“名稱”、“用户屬性”和“令牌名稱”為 DOB。 “聲明 JSON 類型”應設置為 字符串。
點擊“保存”後,我們的映射已就緒。 因此,我們現在可以從 Keycloak 端接收 DOB 作為自定義用户屬性。
在下一部分中,我們將看到如何通過 API 調用訪問它。
2.2. 訪問自定義用户屬性
在基於我們的 Spring Boot 應用程序的基礎上,讓我們添加一個新的 REST 控制器來獲取我們添加的用户的屬性:
@Controller
public class CustomUserAttrController {
@GetMapping(path = "/users")
public String getUserInfo(Model model) {
final DefaultOidcUser user = (DefaultOidcUser) SecurityContextHolder.getContext()
.getAuthentication()
.getPrincipal();
String dob = "";
OidcIdToken token = user.getIdToken();
Map<String, Object> customClaims = token.getClaims();
if (customClaims.containsKey("DOB")) {
dob = String.valueOf(customClaims.get("DOB"));
}
model.addAttribute("username", user.getName());
model.addAttribute("dob", dob);
return "userInfo";
}
}如我們所見,首先我們從安全上下文中獲取了 身份驗證,然後從中提取了 OidcUser。 接下來,我們可以從該 OidcUser 中獲取其 IDToken 和 DOB,這些信息可以從該 IDToken 的 Claims 中提取。
以下是用於顯示這些信息的模板,名為 userInfo.html:
<div id="container">
<h1>Hello, <span th:text="${username}">--name--</span>.</h1>
<h3>Your Date of Birth as per our records is <span th:text="${dob}"/>.</h3>
</div>2.3. 測試
啓動 Boot 應用程序時,請導航至 http://localhost:8081/users。 初始步驟是輸入憑據。
在輸入用户 user1 的憑據後,您將看到以下頁面:
3. 內嵌服務器
現在讓我們看看如何在內嵌 Keycloak 實例上實現相同的功能。
3.1. 添加自定義用户屬性
基本上,我們需要執行相同的步驟,只是我們需要將它們保存為 realm 定義文件中預配置項,即 baeldung-realm.json。
為了將屬性 DOB 添加到用户 [email protected] 中,首先我們需要配置其屬性:
"attributes" : {
"DOB" : "1984-07-01"
},然後添加 DOB 協議映射器:
"protocolMappers": [
{
"id": "c5237a00-d3ea-4e87-9caf-5146b02d1a15",
"name": "DOB",
"protocol": "openid-connect",
"protocolMapper": "oidc-usermodel-attribute-mapper",
"consentRequired": false,
"config": {
"userinfo.token.claim": "true",
"user.attribute": "DOB",
"id.token.claim": "true",
"access.token.claim": "true",
"claim.name": "DOB",
"jsonType.label": "String"
}
}
]這就是我們需要的全部內容。
現在我們已經瞭解了自定義用户屬性添加中授權服務器的部分,接下來我們來探討資源服務器如何訪問用户的出生日期。
3.2. 訪問自定義用户屬性
在資源服務器端,自定義屬性將作為 AuthenticationPrincipal 中的聲明值直接可用。
讓我們編寫一個 API 來實現它:
@RestController
public class CustomUserAttrController {
@GetMapping("/user/info/custom")
public Map<String, Object> getUserInfo(@AuthenticationPrincipal Jwt principal) {
return Collections.singletonMap("DOB", principal.getClaimAsString("DOB"));
}
}3.3. 測試
現在讓我們使用 JUnit 進行測試。
首先我們需要獲取訪問令牌,然後調用資源服務器上的 /user/info/custom</em/> API 端點:
@Test
public void givenUserWithReadScope_whenGetUserInformationResource_thenSuccess() {
String accessToken = obtainAccessToken("read");
Response response = RestAssured.given()
.header(HttpHeaders.AUTHORIZATION, "Bearer " + accessToken)
.get(userInfoResourceUrl);
assertThat(response.as(Map.class)).containsEntry("DOB", "1984-07-01");
}如我們所見,我們驗證了我們收到的出生日期(DOB)值與我們在用户屬性中添加的值完全一致。
4. 結論
在本教程中,我們學習瞭如何在 Keycloak 中為用户添加額外的屬性。
我們觀察到了這兩種情況:獨立實例和嵌入式實例。我們還看到了在兩種情況下,如何通過 REST API 在後端訪問這些自定義聲明。