Keycloak 自定义用户属性
1、概览
Keycloak 是第三方授权服务器,负责管理我们 Web 或移动应用的用户。
它提供了一些默认属性,例如名字、姓氏和电子邮件,用于存储任何给定用户的信息。但是很多时候,这些属性是不够的,我们可能需要添加一些特定于我们应用的额外用户属性。
本文将带你了解如何在 Keycloak 授权服务器中添加自定义用户属性,并在基于 Spring 的后端中访问它们。
2、独立服务器
2.1、添加自定义用户属性
基于上文 “Spring Boot 整合 Keycloak” 中的 Keycloak 服务器。
第一步是进入 Keycloak
的管理控制台。
在 Keycloak 发行版的 bin
文件夹中运行如下命令来启动服务器:
kc.bat start-dev
然后,进入 Web 管理控制台 http://localhost:8180/auth/admin
,输入凭证:initial1
/ zaq1!QAZ
。
接下来,点击 “Manage” 选项卡下的 “Users”:
在这里,可以看到 之前(上一篇文章)添加的用户:user1
。
点击 “ID”,然后转到 “Attributes” 选项卡,添加一个新的属性,即表示出生日期的 “DOB”:
点击 “Save” 后,自定义属性就会添加到用户信息中。
接下来,将此属性作为自定义 Claim 添加到映射中,以便它在用户 Token 的 JSON Payload 中可用。
为此,需要进入管理控制台的 “应用客户端”。回想一下 之前 创建的客户端 login-app
:
点击它,然后选择 “Client scopes” 选项卡。在 “Client scopes” 页面点击 “login-app-dedicated” 链接,进入 “Mappers” 选项卡。点击 “Configure a new mapper”,选择 “User Attribute” 创建新 mapper:
将 Name
、User Attribute
和 Token Claim
名称设为 DOB
。 Claim JSON Type
设置为 String
。
点击 “Save” 后,映射就完成了。现在,可以从 Keycloak 端接收 DOB
作为自定义用户属性了。
2.2、访问自定义用户属性
在 上文 Spring Boot 应用 的基础上,添加一个新的 REST Controller 来获取添加的用户属性:
@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";
}
}
如上,首先从 Security Context 中获取 Authentication
,并从中提取了 OidcUser
。然后,获得了 IDToken
。最后就可以从 IDToken
的 Claims
中提取 DOB
。
下面是显示这些信息的模板,名为 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
中。
要在用户 john@test.com
中添加 DOB
属性,首先需要配置其属性:
"attributes" : {
"DOB" : "1984-07-01"
},
然后为 DOB
添加 Protocol Mapper:
"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"
}
}
]
这就行了。
在知道了如何向授权服务器添加自定义用户属性后,来看一下资源服务器如何访问用户的出生日期(DOB
)。
3.2、访问自定义用户属性
在资源服务器端,自定义属性将作为 AuthenticationPrincipal
中的 Claim(声明)值提供给我们。
定义一个 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 进行测试。首先需要获取 Access Token,然后调用资源服务器上的 /user/info/custom
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 服务器和嵌入式 Keycloak 服务器中为用户添加额外属性,以及如何在资源服务器中访问用户的自定义属性。
Ref:https://www.baeldung.com/keycloak-custom-user-attributes