无法使 Keycloak 客户端启动的客户端帐户链接正常工作
Unable to get Keycloak client initiated client account linking to work
启动客户端发起的帐户链接的请求失败。
控制台显示类型为 CLIENT_INITIATED_ACCOUNT_LINKING_ERROR 的警告,错误为:invalid_token.
url 是由 php 后端系统按照此处所述生成的:https://www.keycloak.org/docs/latest/server_development/#client-initiated-account-linking。
还要确保在生成哈希时使用 UTF8 编码
该部分描述的所有先决条件都已满足。
我正在使用 Keycloak 15.0.2 和 Laravel 与 Socialite 一起对用户进行身份验证。
这就是哈希的生成方式。
$keycloack_user = Socialite::driver('keycloak')->user();
$bearerToken = $keycloack_user->token;
$tokenParts = explode(".", $bearerToken);
$tokenHeader = base64_decode($tokenParts[0]);
$tokenPayload = base64_decode($tokenParts[1]);
$jwtHeader = json_decode($tokenHeader);
$jwtPayload = json_decode($tokenPayload);
$client_id = $jwtPayload->azp;
$host = $jwtPayload->iss;
$session_state = $jwtPayload->session_state;
$nonce = Str::random(20);
$provider = "google";
$input = $nonce . $session_state . $client_id . $provider;
$utf8encoded = utf8_encode($input);
$hashed = hash('sha256', $utf8encoded);
$encoded = rtrim(strtr(base64_encode($hashed), '+/', '-_'), '=');
然后链接url构造如下:
$redirect_uri = urlencode(...);
$full_url = $host . "/broker/". $provider ."/link?client_id=". $client_id ."&redirect_uri=". $redirect_uri ."&nonce=". $nonce ."&hash=" . $encoded;
我目前正在测试我的本地机器,没有为任何应用程序使用 https。登录工作正常,在检查 JWT 令牌时,存在所需的角色映射:
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
但是在访问 url 时它显示“无效请求”并且 Keycloak 控制台指示令牌无效。
更新:解决方案是return哈希方法的结果作为原始二进制数据
$hashed = hash('sha256', $utf8encoded, true);
我最近不得不处理相同的任务,但客户端是在 JavaScript 中实现的。我也被困了很长一段时间,直到我意识到 keycloak 期待编码的哈希值是多么不寻常。您需要考虑以下两点:
- 在base64转换之前将哈希字符串编码为十六进制
- 将
+
替换为 -
,将 /
替换为 _
。除此之外,删除尾随 =
符号
下面是一个用 JS 编写的工作片段:
import sjcl from "sjcl";
hexToBase64(hexstring) {
return btoa(hexstring.match(/\w{2}/g).map(function(a) {
return String.fromCharCode(parseInt(a, 16));
}).join(""));
},
// Assume nonce, session_state, clientId, provider to be given
var data = nonce + session_state + clientId + provider;
var myBitArray = sjcl.hash.sha256.hash(data)
var hashedData = sjcl.codec.hex.fromBits(myBitArray)
var base64HashedData = this.hexToBase64(HashedData)
base64HashedData = base64HashedData.replaceAll('+','-').replaceAll('/','_').replaceAll('=','')
base64HashedData
就是您需要作为散列查询参数传递给 keycloak 的 link
端点的内容。
启动客户端发起的帐户链接的请求失败。
控制台显示类型为 CLIENT_INITIATED_ACCOUNT_LINKING_ERROR 的警告,错误为:invalid_token.
url 是由 php 后端系统按照此处所述生成的:https://www.keycloak.org/docs/latest/server_development/#client-initiated-account-linking。
还要确保在生成哈希时使用 UTF8 编码
该部分描述的所有先决条件都已满足。
我正在使用 Keycloak 15.0.2 和 Laravel 与 Socialite 一起对用户进行身份验证。
这就是哈希的生成方式。
$keycloack_user = Socialite::driver('keycloak')->user();
$bearerToken = $keycloack_user->token;
$tokenParts = explode(".", $bearerToken);
$tokenHeader = base64_decode($tokenParts[0]);
$tokenPayload = base64_decode($tokenParts[1]);
$jwtHeader = json_decode($tokenHeader);
$jwtPayload = json_decode($tokenPayload);
$client_id = $jwtPayload->azp;
$host = $jwtPayload->iss;
$session_state = $jwtPayload->session_state;
$nonce = Str::random(20);
$provider = "google";
$input = $nonce . $session_state . $client_id . $provider;
$utf8encoded = utf8_encode($input);
$hashed = hash('sha256', $utf8encoded);
$encoded = rtrim(strtr(base64_encode($hashed), '+/', '-_'), '=');
然后链接url构造如下:
$redirect_uri = urlencode(...);
$full_url = $host . "/broker/". $provider ."/link?client_id=". $client_id ."&redirect_uri=". $redirect_uri ."&nonce=". $nonce ."&hash=" . $encoded;
我目前正在测试我的本地机器,没有为任何应用程序使用 https。登录工作正常,在检查 JWT 令牌时,存在所需的角色映射:
"account": {
"roles": [
"manage-account",
"manage-account-links",
"view-profile"
]
}
但是在访问 url 时它显示“无效请求”并且 Keycloak 控制台指示令牌无效。
更新:解决方案是return哈希方法的结果作为原始二进制数据
$hashed = hash('sha256', $utf8encoded, true);
我最近不得不处理相同的任务,但客户端是在 JavaScript 中实现的。我也被困了很长一段时间,直到我意识到 keycloak 期待编码的哈希值是多么不寻常。您需要考虑以下两点:
- 在base64转换之前将哈希字符串编码为十六进制
- 将
+
替换为-
,将/
替换为_
。除此之外,删除尾随=
符号
下面是一个用 JS 编写的工作片段:
import sjcl from "sjcl";
hexToBase64(hexstring) {
return btoa(hexstring.match(/\w{2}/g).map(function(a) {
return String.fromCharCode(parseInt(a, 16));
}).join(""));
},
// Assume nonce, session_state, clientId, provider to be given
var data = nonce + session_state + clientId + provider;
var myBitArray = sjcl.hash.sha256.hash(data)
var hashedData = sjcl.codec.hex.fromBits(myBitArray)
var base64HashedData = this.hexToBase64(HashedData)
base64HashedData = base64HashedData.replaceAll('+','-').replaceAll('/','_').replaceAll('=','')
base64HashedData
就是您需要作为散列查询参数传递给 keycloak 的 link
端点的内容。