iOS Developer的全栈之路 - Keycloak(5)

2020-01-12  本文已影响0人  西西的一天

在上一节中,使用Keycloak保护了SpringBoot的RestAPI,其中的用户和角色都是通过Keycloak内置的web页面进行添加的。在本节中,将使用RestAPI来创建用户并为用户分配角色。

Create User Endpoint

创建用户的Endpoint:http://localhost:8080/auth/admin/realms/{realmName}/users,在我的demo中realmName为springboot-integration,所以完整的url为:http://localhost:8080/auth/admin/realms/springboot-integration/users,这是一个POST请求,那么body需要传入是什么呢?通过官方文档,需要的body类型为UserRepresentation,body如下所示:

{
    "firstName": "xyz",
    "lastName": "xyz",
    "username": "xyz",
    "email": "demo@gmail.com",
    "enabled": "true",
    "credentials": [
        {
            "type": "password",
            "value": "123456",
            "temporary": false
        }
    ],
    "realmRoles": [
        "user"
    ]
}

通过如上的POST请教会得到一个401的错误,回看url,可以发现只有admin的用户才可创建用户。

获取Token

获取admin的token和上节中获取普通用户的token是相同的,url:http://localhost:8080/auth/realms/master/protocol/openid-connect/token,并使用x-www-form-urlencoding编码方式发生post请求,如下图所示:

admin token.png
获得access token后,重新发起创建用户的请求,当传入用户名不存在时,便可成功创建用户,成功的response是一个空body,status code为201,表示创建成功。

通过Keycloak的web登录后,会发现,请求中带有的realmRoles并没有生效,查阅想过issue时,发现这是官方暂不支持的一个参数,链接:https://issues.redhat.com/browse/KEYCLOAK-12460,从comment中看到:

The rest endpoints have never supported adding roles as part of creating a new user, so changing this to a enhancement request. A contribution to this if tests are included would be welcome.

若需要这个功能看来只能fork过来改一下了,退而求其次,只能再多发一个请求RoleMappers,这个有点尴尬,如果第一个请求成功,第二请求失败,应该如何处理这个结果呢。希望有时间可以创建这个PR~

Map a Role To a User

官方给出的endpoint:http://localhost:8080/auth/admin/realms/{realmName}/users/{userId}/role-mappings/realm
其中需要一个UserId,而在创建时,返回的response为空,那么又需要一个request来获取UserId:
http://localhost:8080/auth/admin/realms/springboot-integration/users?username=xyz这是一个GET请求,得到的response如下所示:

[
    {
        "id": "15c16b3d-dafe-496e-8c9e-98933b4cd518",
        "createdTimestamp": 1578820379997,
        "username": "xyz",
        "enabled": true,
        "totp": false,
        "emailVerified": false,
        "firstName": "xyz",
        "lastName": "xyz",
        "email": "demo2@gmail.com",
        "disableableCredentialTypes": [],
        "requiredActions": [],
        "notBefore": 0,
        "access": {
            "manageGroupMembership": true,
            "view": true,
            "mapRoles": true,
            "impersonate": true,
            "manage": true
        }
    }
]

终于拿到了userId,继续添加role:
http://localhost:8080/auth/admin/realms/springboot-integration/users/15c16b3d-dafe-496e-8c9e-98933b4cd518/role-mappings/realm需要的body,如下所示:

{
    "roles": [
        {
            "name": "user",
            "clientRole": false
        }
    ]
}

本以为,可以成功添加,可是直接报错,真的是要吐槽Keycloak的官方文档了。通过chrome的network调试工具,看看在网页端是如何发起添加role的请求的,发现playload的格式是这样的:

[{
    "id": "66633ad6-7412-4176-aa25-0c1ff67a2180",
    "name": "user",
    "description": "normal user",
    "composite": false,
    "clientRole": false,
    "containerId": "springboot-integration"
}]

根据文档所述,这些role的字段都不是必须得,如果当前只知道role name,是否可以呢?body中只留下name,发送请求,报错:"error": "Role not found",不禁感叹文档有何用
所以这些字段都是需要的,那么问题又来了,我们如何找到需要的role呢?这次直接忽略文档,chrome network调试工具走起。
GET请求http://localhost:8080/auth/admin/realms/springboot-integration/roles可获得当前realm下的所有role。

[
    {
        "id": "195d5f3e-e805-4f53-88c0-e3589b9172c4",
        "name": "admin",
        "description": "administrator, super user",
        "composite": true,
        "clientRole": false,
        "containerId": "springboot-integration"
    },
    {
        "id": "814d6190-3d69-4e9b-aaae-ef60ae12159e",
        "name": "Member",
        "composite": false,
        "clientRole": false,
        "containerId": "springboot-integration"
    },
    {
        "id": "ac6827fb-51b9-436c-8cb8-852babd4816b",
        "name": "offline_access",
        "description": "${role_offline-access}",
        "composite": false,
        "clientRole": false,
        "containerId": "springboot-integration"
    },
    {
        "id": "98107db5-7f81-4fd9-beb0-ea4fd3d0fccd",
        "name": "uma_authorization",
        "description": "${role_uma_authorization}",
        "composite": false,
        "clientRole": false,
        "containerId": "springboot-integration"
    },
    {
        "id": "66633ad6-7412-4176-aa25-0c1ff67a2180",
        "name": "user",
        "description": "normal user",
        "composite": false,
        "clientRole": false,
        "containerId": "springboot-integration"
    },
    {
        "id": "13bc2555-a3d8-4975-9cce-ae2251bca1b2",
        "name": "Librarian",
        "composite": true,
        "clientRole": false,
        "containerId": "springboot-integration"
    }
]

总结

当需要创建一个用户时,首先需要admin用户的token,之后需要一系列的请求:

  1. 创建用户: http://localhost:8080/auth/admin/realms/springboot-integration/users
  2. 根据用户名,获取当前用户的完整信息: http://localhost:8080/auth/admin/realms/springboot-integration/users?username=xyz
  3. 获取当前realm下所有的role: http://localhost:8080/auth/admin/realms/springboot-integration/roles
  4. 为用户添加role: http://localhost:8080/auth/admin/realms/springboot-integration/users/15c16b3d-dafe-496e-8c9e-98933b4cd518/role-mappings/realm

真的是一口老血 ~

上一篇下一篇

猜你喜欢

热点阅读