Keycloak:使用 keycloak-admin 为用户生成访问令牌
Posted
技术标签:
【中文标题】Keycloak:使用 keycloak-admin 为用户生成访问令牌【英文标题】:Keycloak: Generate access token for a user with keycloak-admin 【发布时间】:2021-04-19 04:30:29 【问题描述】:我必须将旧式身份验证系统移至 Keycloak,并且我无法更改客户端上的实际工作流程。因此,我需要为我的 api(在 node.js 中)提供一个用户创建和登录系统,该系统依次代表用户从 Keycloak 创建和获取访问令牌。
我能够创建用户,但我无法找到为该用户生成访问令牌的方法。我找到的唯一解决方法是创建一个用户并设置一个随机密码,然后要求授予用户提供用户名和密码,但这意味着我必须在我身边存储一个密码,这正是我想搬家的原因到钥匙斗篷。
const KcAdminClient = require('keycloak-admin').default;
const Keycloak = require('keycloak-connect');
const _keycloakAdmin = new KcAdminClient(
baseUrl: process.env.KEYCLOAK_SERVER_AUTH_URL,
realm: process.env.KEYCLOAK_REALM
);
await _keycloakAdmin.auth(
realm: process.env.KEYCLOAK_REALM,
username: process.env.KEYCLOAK_USER,
password: process.env.KEYCLOAK_PASSWORD,
grantType: 'password',
clientId: process.env.KEYCLOAK_CLIENT_ID,
);
//Create a user and set password
const newUser = await _keycloakAdmin.users.create(
realm: process.env.KEYCLOAK_REALM,
username: 'something',
email: 'someone@domain.com',
firstName: 'Some',
lastName: 'One',
emailVerified: true,
enabled: true,
);
await _keycloakAdmin.users.resetPassword(
realm: process.env.KEYCLOAK_REALM,
id: newUser.id,
credential:
temporary: false,
type: 'password',
value: 'randompassword'
);
//generate a token for the user
const _keycloak = new Keycloak(,
clientId: process.env.KEYCLOAK_CLIENT_ID,
serverUrl: process.env.KEYCLOAK_SERVER_AUTH_URL,
realm: process.env.KEYCLOAK_REALM,
credentials:
secret: process.env.KEYCLOAK_CLIENT_SECRET
);
const grant = await _keycloak.grantManager.obtainDirectly('something', 'randompassword');
const access_token = grant.access_token.token;
我不敢相信没有更优雅的方式来做到这一点,所以我认为我在配置 Keycloak 客户端以及理解一些基本概念和命名约定方面缺少一些基本知识。我本来期望像
await _keycloakAdmin.users.generateAccessToken(userId, realm, clientId, ...)
但我找不到它。我只在这里找到了这个未回答的问题:Keycloak :REST API call to get access token of a user through admin username and password
【问题讨论】:
【参考方案1】:该解决方案相当复杂,需要(在撰写本文时)激活名为 Token Exchange 的 Keycloak 的“预览”功能。该过程在https://www.keycloak.org/docs/latest/securing_apps/index.html#_token-exchange 进行了描述,对于我的具体情况,我按照https://www.keycloak.org/docs/latest/securing_apps/index.html#internal-token-to-internal-token-exchange 的说明进行操作。
首先,您需要启用令牌交换功能,在运行 Keycloak 时将开关 -Dkeycloak.profile=preview
添加到 JAVA_OPTS
。要检查 Keycloak 是否加载了预览功能,请查看部分配置文件下 /auth/admin/master/console/#/server-info
的服务器信息:
令牌交换的想法是,您为您的领域的管理员获取令牌,然后将其交换为“普通”用户的令牌。 为此,您必须为您的 Keycloak 领域创建(如果您还没有)两个不同的客户端:第一个是管理员用来获取令牌的“起始客户端”,第二个是“目标客户端”您想要“普通”用户的令牌。
之后,您需要为您的领域创建一个管理员用户。您可以按照Keycloak - Create Admin User in a Realm的说明进行操作
然后你需要让目标客户端接受令牌交换。您应该仔细按照https://www.keycloak.org/docs/latest/securing_apps/index.html#_client_to_client_permission 的说明进行操作
这是一个两步过程:创建客户端策略,指定哪些“启动客户端”可以交换令牌,然后为目标客户端启用权限并将刚刚创建的策略附加到 token-exchange
权限:
设置完 Keycloak 后,您实际上可以发出两个调用,首先为领域的管理员获取令牌,然后为具有特定 userId 的用户获取令牌。
获取管理员令牌
curl --location --request POST '<your_url>/auth/realms/<your_realm>/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=password' \
--data-urlencode 'client_id=<your_starting_client>' \
--data-urlencode 'username=<your_admin_username>' \
--data-urlencode 'password=<your_admin_password>' \
--data-urlencode 'realm=<your_realm>' \
--data-urlencode 'scope=openid'
将管理员令牌换成“普通”用户令牌
curl --location --request POST '<your_url>/auth/realms/<your_realm>/protocol/openid-connect/token' \
--header 'Content-Type: application/x-www-form-urlencoded' \
--data-urlencode 'grant_type=urn:ietf:params:oauth:grant-type:token-exchange' \
--data-urlencode 'client_id=<your_starting_client>' \
--data-urlencode 'subject_token=<your_admin_token>' \
--data-urlencode 'requested_token_type=urn:ietf:params:oauth:token-type:refresh_token' \
--data-urlencode 'audience=<your_target_client>' \
--data-urlencode 'requested_subject=<your_target_user_id>'
根据您的客户端配置,您最终可能必须在第二次调用中指定client_secret
。
【讨论】:
以上是关于Keycloak:使用 keycloak-admin 为用户生成访问令牌的主要内容,如果未能解决你的问题,请参考以下文章
除了 keycloak 令牌之外,我还需要其他任何东西来访问使用 keycloak 保护的服务吗?
如何使用 Angular -> Spring Boot Oauth2 -> Keycloak 获取 keycloak 令牌