如何配置 Keycloak 并通过 REST API 完成所有步骤并获得 JWT?

Posted

技术标签:

【中文标题】如何配置 Keycloak 并通过 REST API 完成所有步骤并获得 JWT?【英文标题】:How do I configure Keycloak and get a JWT with all steps done through the REST API? 【发布时间】:2021-04-04 05:08:22 【问题描述】:

我需要为在 Docker 中运行的 Keycloak 配置一个领域、一个具有凭据的用户和一个客户端,然后像 blog post 一样获取 JWT。如果我使用如图所示的 UI,它可以工作,但我需要通过 Keycloak REST API 自动执行所有步骤。当我这样做时,所有步骤似乎都有效,但获取 JWT 失败。

我像这样在 Docker 中运行 Keycloak

docker network create keycloak-network

docker run --name mysql -d \
  --net keycloak-network \
  -e MYSQL_DATABASE=keycloak \
  -e MYSQL_USER=keycloak \
  -e MYSQL_PASSWORD=password \
  -e MYSQL_ROOT_PASSWORD=root_password \
  mysql:8.0.22

docker run -d -it \
  -e DB_VENDOR=mysql \
  -e KEYCLOAK_USER=admin \
  -e KEYCLOAK_PASSWORD=admin \
  --name keycloak \
  --net keycloak-network \
  -p 8080:8080 \
  jboss/keycloak:11.0.3

我从主域获取访问令牌

POST -H "Content-Type: application/x-www-form-urlencoded" -d "username=admin" -d "password=admin" -d "grant_type=password" -d 'client_id=admin-cli' "http://localhost:8080/auth/realms/master/protocol/openid-connect/token"|jq -r '.access_token'

然后我创建我的领域(命名为testrealm

POST -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -d @"$REALM_FILE" "http://localhost:8080/auth/admin/realms"

然后我创建一个具有凭据的用户:

POST "http://localhost:8080/auth/admin/realms/testrealm/users" --header 'Content-Type: application/json' -H "Authorization: Bearer $ACCESS_TOKEN" -d "enabled":true,"username":"testuser","email":"test.user@gmail.com","firstName":"test","lastName":"user","credentials":["type":"password","value":"abc123","temporary":false]

我可以在 UI 中看到新用户,并在新用户凭据中看到一个输入密码的条目。

我创建了一个客户端(名为testclient

POST -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" -d @"$CLIENT_FILE" "http://localhost:8080/auth/admin/realms/testrealm/clients"

我获得了修改新客户端所需的 ID

GET -H "Accept: application/json" -H "Authorization: Bearer $ACCESS_TOKEN" "http://localhost:8080/auth/admin/realms/testrealm/authentication/flows"

从别名 browser 中提取 BROWSER_ID,从别名 direct grant 中提取 DIRECT_GRANT_ID。

我更新客户端,将Access Type 更改为confidential,并使用Authentication Flow Overrides 更改Browser FlowDirect Grant Flow

PUT -H "Authorization: Bearer $ACCESS_TOKEN" -H "Content-Type: application/json" --data @client.update.json "http://localhost:8080/auth/admin/realms/testrealm/clients/$clientId"

数据在哪里

                                                                               
    "publicClient": false,        
    "clientAuthenticatorType": "client-secret",                                            
    "authenticationFlowBindingOverrides":                                                                  
        "direct_grant":"$DIRECT_GRANT_ID",
        "browser":"$BROWSER_ID"
    
 

我通过

获取客户端密码
GET -H "Accept: application/json" -H "Authorization: Bearer $ACCESS_TOKEN" http://localhost:8080/auth/admin/realms/testrealm/clients/$CLIENT_ID/client-secret

此时,如果我进入 UI,它会显示我返回的相同客户端密码,并且客户端 Access Typeconfidential,而 Authentication Flow Overrides 设置为 browserdirect grant。一切看起来都是正确的。现在,Keycloak 服务器的配置应该与通过 UI 完成时的配置相同,如博文所示。

当我使用帖子中显示的 curl 命令获取 JWT 时

curl -L -X POST http://localhost:8080/auth/realms/testrealm/protocol/openid-connect/token -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'client_id=testclient' --data-urlencode 'grant_type=password' --data-urlencode 'client_secret=544479de-72a4-44c7-9420-3a142cd699c6' --data-urlencode 'scope=openid' --data-urlencode 'username=testuser' --data-urlencode 'password=abc123'

给出一个错误,说 https 是必需的。

"error":"invalid_request","error_description":"HTTPS required"

但通过 UI 完成配置时不需要 https。事实上所有的请求都是通过 http 发送的,而不是 https。

然后使用https

curl -L -X POST https://localhost:8080/auth/realms/testrealm/protocol/openid-connect/token -H 'Content-Type: application/x-www-form-urlencoded' --data-urlencode 'client_id=testclient' --data-urlencode 'grant_type=password' --data-urlencode 'client_secret=544479de-72a4-44c7-9420-3a142cd699c6' --data-urlencode 'scope=openid' --data-urlencode 'username=testuser' --data-urlencode 'password=abc123'

我收到此错误

curl: (35) error:1408F10B:SSL routines:ssl3_get_record:wrong version number

如果我通过 UI 配置 Keycloak,curl 命令可以工作,所以我在使用REST API 时一定错过了一些东西。 Keycloak 文档没有显示这个用例,所以它们在这里没有帮助。

有人知道我在使用REST API 时错过了什么吗?

【问题讨论】:

从 http 更改为 https 时,我应该将端口更改为 8443。该端口必须从 docker 共享,如下面的答案所示。 【参考方案1】:

发布 Keycloak 容器的 8443 端口。将有带有自签名证书的 https(因此在您的请求中禁用 tls 验证):

docker run -d -it \
 -e DB_VENDOR=mysql \
 -e KEYCLOAK_USER=admin \
 -e KEYCLOAK_PASSWORD=admin \
 --name keycloak \
 --net keycloak-network \
 -p 8443:8443 \
 jboss/keycloak:11.0.3

Keycloak 将在https://localhost:8443 上提供。见Keycloak Docker HTTPS required

【讨论】:

好收获。这仍然留下了一个谜,为什么当我通过 UI 配置时我可以使用端口 8080,但当我使用 REST API 配置时我必须使用端口 8443。

以上是关于如何配置 Keycloak 并通过 REST API 完成所有步骤并获得 JWT?的主要内容,如果未能解决你的问题,请参考以下文章

通过 REST 与 Keycloak 保护的后端进行后端到后端通信

如何在没有管理员帐户的情况下通过 REST 获取 Keycloak 用户

如何通过 REST API 将 Keycloak 领域角色添加到组

如何通过执行操作电子邮件通过 keycloak admin rest api 更新密码

使用 JAVA 通过 REST API 集成 Keycloak 时在 toRepresentation() 处获取 404

如何从 REST API(PUT 方法)更新 Keycloak 密码?