使用Keycloak自定义用户属性

2023/05/12

1. 概述

Keycloak是第三方授权服务器,用于管理我们的Web或移动应用程序的用户。

它提供了一些默认属性,例如要为任何给定用户存储的名字、姓氏和电子邮件。但很多时候,这些还不够,我们可能需要添加一些特定于我们的应用程序的额外用户属性。

在本教程中,我们将了解如何将自定义用户属性添加到我们的Keycloak授权服务器并在基于Spring的后端访问它们

首先,我们将在独立的Keycloak服务器上演示它,然后在嵌入式服务器上实现相同的目的。

2. 独立服务器

2.1 添加自定义用户属性

这里的第一步是转到Keycloak的管理控制台,为此,我们需要通过从Keycloak发行版的bin文件夹中运行以下命令来启动服务器:

./standalone.sh -Djboss.socket.binding.port-offset=100

然后我们需要转到管理控制台并输入initial1/zaq1!QAZ凭据。

接下来,我们将单击“Manage”选项卡下的“Users”,然后单击“User list”:

在这里我们可以看到我们之前添加的用户user1。

现在让我们点击用户名并转到“Attributes”选项卡以添加一个新的ID,出生日期为DOB:

单击Save后,自定义属性将添加到用户的信息中。

接下来,我们需要为此属性添加一个映射作为自定义声明,以便它在用户令牌的JSON负载中可用。

为此,我们需要在管理控制台上转到应用程序的Clients,回想一下,我们之前创建了一个客户端login-app:

现在,让我们单击它并转到其Client scopes选项卡:

然后点击login-app-dedicated进入到Mappers选项卡:

然后点击Configure a new mapper:

最后在Configure a new mapper窗口选择User Attribute:

首先,我们将选择Mapper type作为User Attribute,然后将Name、User Attribute和Token Claim Name设置为DOB,并且Claim JSON Type应设置为String。

单击Save后,我们的映射就准备好了。所以现在,我们从Keycloak端配备了接收DOB作为自定义用户属性的功能。

在下一节中,我们将了解如何通过API调用访问它

2.2 访问自定义用户属性

在我们的Spring Boot应用程序之上构建,让我们添加一个新的REST控制器来获取我们添加的用户属性:

@Controller
public class CustomUserAttrController {

    @GetMapping(path = "/users")
    public String getUserInfo(Model model) {
        KeycloakAuthenticationToken authentication = (KeycloakAuthenticationToken) 
              SecurityContextHolder.getContext().getAuthentication();

        Principal principal = (Principal) authentication.getPrincipal();
        String dob="";

        if (principal instanceof KeycloakPrincipal) {
            KeycloakPrincipal kPrincipal = (KeycloakPrincipal) principal;
            IDToken token = kPrincipal.getKeycloakSecurityContext().getIdToken();

            Map<String, Object> customClaims = token.getOtherClaims();

            if (customClaims.containsKey("DOB")) {
                dob = String.valueOf(customClaims.get("DOB"));
            }
        }

        model.addAttribute("username", principal.getName());
        model.addAttribute("dob", dob);
        return "userInfo";
    }
}

如我们所见,这里我们首先从SecurityContextHolder中获取了KeycloakAuthenticationToken,然后从中提取了Principal,在将其转换为KeycloakPrincipal后,我们获得了它的IDToken。

然后可以从此IDToken的OtherClaims中提取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定义文件tuyucheng-realm.json中

要将属性DOB添加到我们的用户john@test.com,首先,我们需要配置它的属性:

"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"
        }
    }
]

这就是我们在这里所需要的。

现在我们已经看到了添加自定义用户属性的授权服务器部分,是时候看看资源服务器如何访问用户的DOB了。

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 API端点:

@Test
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中访问这些自定义声明。

与往常一样,本教程的完整源代码可在GitHub上获得。

Show Disqus Comments

Post Directory

扫码关注公众号:Taketoday
发送 290992
即可立即永久解锁本站全部文章