PHP 中的 BOX 的 JWT 服务器身份验证签名验证失败
JWT Server Authentication Signature validation failed for BOX in PHP
我在 PHP 中遇到 JWT 签名验证问题。
这是我的代码
// Create token header as a JSON string
$header = ["alg" => "RS256",
"typ" => "JWT",
"kid" => "gnkp02u2"];
$header = json_encode((object) $header);
// Create token payload as a JSON string
$payload = [
"typ" => "jwt",
"kid" => "gnkp02u2",
"iss" => "op63g1amchcxy456oei2tkfk1lg4dbxy",
"aud" => "https://api.box.com/oauth2/token",
"jti" => "4f1g23a12aa854rtyuil",
"exp" => time() + 30,
"sub" => "23527187",
"box_sub_type" => "enterprise"];
$payload = json_encode((object) $payload);
// Encode Header to Base64Url String
$base64UrlHeader = str_replace(["+", "/", "="], ["-", "_", ""],
base64_encode($header));
// Encode Payload to Base64Url String
$base64UrlPayload = str_replace(["+", "/", "="], ["-", "_", ""],
base64_encode($payload));
$headerPayload = $base64UrlHeader . "." . $base64UrlPayload;
//$headerPayload = base64_encode($header) . "." . base64_encode($payload);
// Create Signature Hash
$privateKey = "file://private.key";
try{
$privateKeyResource = openssl_get_privatekey($privateKey,
"73bed4ee2b994f5fdf0ddef660d8f935");
$result = openssl_sign($headerPayload, $signature, $privateKeyResource, OPENSSL_ALGO_SHA256);
if ($result === false)
{
var_dump($result);
throw new RuntimeException("Failed to generate signature: ".implode("\n", getOpenSSLErrors()));
}
$signatureEncoded = base64_encode($signature);
$jwt = "$base64UrlHeader.$base64UrlPayload.$signatureEncoded";
}
catch(Exception $e){
print_r($e->getMessage());
}
print_r( $jwt );`
并生成
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imdua3AwMnUyIn0.eyJ0eXAiOiJqd3QiLCJraWQiOiJnbmtwMDJ1MiIsImlzcyI6Im9wNjNnMWFtY2hjeHk0NTZvZWkydGtmazFsZzRkYnh5IiwiYXVkIjoiaHR0cHM6XC9cL2FwaS5ib3guY29tXC9vYXV0aDJcL3Rva2VuIiwianRpIjoiNGYxZzIzYTEyYWE4NTRydHl1aWwiLCJleHAiOjE1MjIwODI5OTUsInN1YiI6IjIzNTI3MTg3IiwiYm94X3N1Yl90eXBlIjoiZW50ZXJwcmlzZSJ9.JMH1sXHrAsT9dURJF/5sOgl2k+qFX/wiqwER4RZwdtxLkLDXDJTzFGZuLPW8JMKqdzntc9hIdc/RHQOla2mi4s1WiGEj/9T1gBPWhjTd4kiZgEenLsZUuLFG77wlzdNPQnm3jON7kM08EfQZU+YYhGDF6JVJ2yH31zkJZqucdbg9Ne43OYPMKEmfa1bKJ3/QmLZXHIEgTYGhh78RsbzViJq3wCqWtUOmksDxCz7/400ZDrmQRH1JIEJW1W6A1oAjPEJVSTniw6a60VVTDXW3WUI0TN68CG5PuNzTXEJcBgnfr1J4yVWeat4rArEyOFsLoyOgBSIu0IHcMRo/V4Md4w==
我在 curl 中像这样使用这个断言
$ curl https://api.box.com/oauth2/token -d 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&client_id=op63g1amchcxy456oei2tkfk1lg4dbxy&client_secret=R7MGxLa7dAZfz5YbXMMPf6a6m8OcYZ2K&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imdua3AwMnUyIn0.eyJ0eXAiOiJqd3QiLCJraWQiOiJnbmtwMDJ1MiIsImlzcyI6Im9wNjNnMWFtY2hjeHk0NTZvZWkydGtmazFsZzRkYnh5IiwiYXVkIjoiaHR0cHM6XC9cL2FwaS5ib3guY29tXC9vYXV0aDJcL3Rva2VuIiwianRpIjoiNGYxZzIzYTEyYWE4NTRydHl1aWwiLCJleHAiOjE1MjIwODI5OTUsInN1YiI6IjIzNTI3MTg3IiwiYm94X3N1Yl90eXBlIjoiZW50ZXJwcmlzZSJ9.JMH1sXHrAsT9dURJF/5sOgl2k+qFX/wiqwER4RZwdtxLkLDXDJTzFGZuLPW8JMKqdzntc9hIdc/RHQOla2mi4s1WiGEj/9T1gBPWhjTd4kiZgEenLsZUuLFG77wlzdNPQnm3jON7kM08EfQZU+YYhGDF6JVJ2yH31zkJZqucdbg9Ne43OYPMKEmfa1bKJ3/QmLZXHIEgTYGhh78RsbzViJq3wCqWtUOmksDxCz7/400ZDrmQRH1JIEJW1W6A1oAjPEJVSTniw6a60VVTDXW3WUI0TN68CG5PuNzTXEJcBgnfr1J4yVWeat4rArEyOFsLoyOgBSIu0IHcMRo/V4Md4w==' -X POST
作为回应,我收到了这个错误
{"error":"invalid_grant","error_description":"Signature verification error. The public key identified by \"kid\" must correspond to the private key used for signing."}
连kid都给对了
我不知道我做错了什么
我已经使用 https://github.com/firebase/php-jwt 存储库解决了 Box JWT 令牌问题,并且工作正常。
use \Firebase\JWT\JWT;
class BoxApi
{
public $authorize_url = 'https://account.box.com/api/oauth2/authorize';
public $token_url = 'https://api.box.com/oauth2/token';
public $api_url = 'https://api.box.com/2.0';
public $upload_url = 'https://upload.box.com/api/2.0';
public $access_token;
public $filename;
public $passPhrase;
public $clientId;
public $clientSecret;
public $accessType;
public $accessTypeId;
public $publicKeyId;
public function __construct($filename, $passPhrase, $clientId, $clientSecret, $accessType = "enterprise", $accessTypeId, $publicKeyId)
{
$this->filename = $filename;
$this->passPhrase = $passPhrase;
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
$this->accessType = $accessType;
$this->accessTypeId = $accessTypeId;
$this->publicKeyId = $publicKeyId;
self::getAccessToken();
}
/* Get AccessToken by JWT*/
public function getAccessToken()
{
$private_key_file = $this->filename;
$fp = fopen ($private_key_file, "r");
if (!$fp)
{
die("Unable to open file");
}
$raw_key_data = fread ($fp, filesize ($private_key_file));
fclose ($fp);
$privateKey = openssl_get_privatekey($raw_key_data , $this->passPhrase);
define("FIREBASE_PRIVATE_KEY", $privateKey);
$token = array(
"iss" => $this->clientId,
"aud" => "https://api.box.com/oauth2/token",
"jti" => sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
),
"exp" => time() + 30,
"sub" => $this->accessTypeId,
"box_sub_type" => $this->accessType
);
$jwt = JWT::encode($token, FIREBASE_PRIVATE_KEY, 'RS256', $this->publicKeyId);
$params = 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&client_id=' . $this->clientId . '&client_secret=' . $this->clientSecret . '&assertion=' . $jwt;
$token = json_decode(self::httpClient("POST", $this->token_url, $params), true);
print "<pre>";
print_r($token);
print "</pre>";
$this->access_token = $token["access_token"];
}
/* Sets the required before biulding the query */
private function set_opts(array $opts)
{
if (!array_key_exists('access_token', $opts)) {
$opts['access_token'] = $this->access_token;
}
return $opts;
}
/* Builds the URL for the call */
private function build_url($api_func, array $opts = array(), $url = null)
{
print "build uri";
$opts = $this->set_opts($opts);
if (isset($url)) {
$base = $url . $api_func . '?';
} else {
$base = $this->api_url . $api_func . '?';
}
$query_string = http_build_query($opts);
$base = $base . $query_string;
return $base;
}
/* Uploads a file */
public function put_file($filename, $parent_id)
{
$file = defined('PHP_MAJOR_VERSION') && PHP_MAJOR_VERSION >= 5 ? new CurlFile(realpath($filename)) : '@/' . realpath($filename);
$url = $this->build_url('/files/content', array(), $this->upload_url);
$params = array('filename' => $file, 'name' => basename($filename), 'parent_id' => $parent_id, 'access_token' => $this->access_token);
return json_decode($this->httpClient("post", $url, $params), true);
}
/* Create a new folder */
public function create_folder($name, $parent_id)
{
$url = $this->build_url("/folders");
$params = array('name' => $name, 'parent' => array('id' => $parent_id));
return json_decode($this->httpClient("post", $url, json_encode($params)), true);
}
/* Modifies the folder details as per the api */
public function update_folder($folder, array $params)
{
$url = $this->build_url("/folders/$folder");
return json_decode($this->httpClient("put", $url, $params), true);
}
/* Shares a folder */
public function share_folder($folder, array $params)
{
$url = $this->build_url("/folders/$folder");
return json_decode($this->httpClient("put", $url, $params), true);
}
/* Shares a file */
public function share_file($file, array $params)
{
$url = $this->build_url("/files/$file");
return json_decode($this->httpClient("put", $url, $params), true);
}
/* Curl Api calls */
private static function httpClient($method, $url, $params = null)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
if (strcasecmp($method, "POST") == 0) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
} elseif (strcasecmp($method, "PUT") == 0) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
} elseif (strcasecmp($method, "DELETE") == 0) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
}
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
}
?>
我在 PHP 中遇到 JWT 签名验证问题。 这是我的代码
// Create token header as a JSON string
$header = ["alg" => "RS256",
"typ" => "JWT",
"kid" => "gnkp02u2"];
$header = json_encode((object) $header);
// Create token payload as a JSON string
$payload = [
"typ" => "jwt",
"kid" => "gnkp02u2",
"iss" => "op63g1amchcxy456oei2tkfk1lg4dbxy",
"aud" => "https://api.box.com/oauth2/token",
"jti" => "4f1g23a12aa854rtyuil",
"exp" => time() + 30,
"sub" => "23527187",
"box_sub_type" => "enterprise"];
$payload = json_encode((object) $payload);
// Encode Header to Base64Url String
$base64UrlHeader = str_replace(["+", "/", "="], ["-", "_", ""],
base64_encode($header));
// Encode Payload to Base64Url String
$base64UrlPayload = str_replace(["+", "/", "="], ["-", "_", ""],
base64_encode($payload));
$headerPayload = $base64UrlHeader . "." . $base64UrlPayload;
//$headerPayload = base64_encode($header) . "." . base64_encode($payload);
// Create Signature Hash
$privateKey = "file://private.key";
try{
$privateKeyResource = openssl_get_privatekey($privateKey,
"73bed4ee2b994f5fdf0ddef660d8f935");
$result = openssl_sign($headerPayload, $signature, $privateKeyResource, OPENSSL_ALGO_SHA256);
if ($result === false)
{
var_dump($result);
throw new RuntimeException("Failed to generate signature: ".implode("\n", getOpenSSLErrors()));
}
$signatureEncoded = base64_encode($signature);
$jwt = "$base64UrlHeader.$base64UrlPayload.$signatureEncoded";
}
catch(Exception $e){
print_r($e->getMessage());
}
print_r( $jwt );`
并生成
eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imdua3AwMnUyIn0.eyJ0eXAiOiJqd3QiLCJraWQiOiJnbmtwMDJ1MiIsImlzcyI6Im9wNjNnMWFtY2hjeHk0NTZvZWkydGtmazFsZzRkYnh5IiwiYXVkIjoiaHR0cHM6XC9cL2FwaS5ib3guY29tXC9vYXV0aDJcL3Rva2VuIiwianRpIjoiNGYxZzIzYTEyYWE4NTRydHl1aWwiLCJleHAiOjE1MjIwODI5OTUsInN1YiI6IjIzNTI3MTg3IiwiYm94X3N1Yl90eXBlIjoiZW50ZXJwcmlzZSJ9.JMH1sXHrAsT9dURJF/5sOgl2k+qFX/wiqwER4RZwdtxLkLDXDJTzFGZuLPW8JMKqdzntc9hIdc/RHQOla2mi4s1WiGEj/9T1gBPWhjTd4kiZgEenLsZUuLFG77wlzdNPQnm3jON7kM08EfQZU+YYhGDF6JVJ2yH31zkJZqucdbg9Ne43OYPMKEmfa1bKJ3/QmLZXHIEgTYGhh78RsbzViJq3wCqWtUOmksDxCz7/400ZDrmQRH1JIEJW1W6A1oAjPEJVSTniw6a60VVTDXW3WUI0TN68CG5PuNzTXEJcBgnfr1J4yVWeat4rArEyOFsLoyOgBSIu0IHcMRo/V4Md4w==
我在 curl 中像这样使用这个断言
$ curl https://api.box.com/oauth2/token -d 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&client_id=op63g1amchcxy456oei2tkfk1lg4dbxy&client_secret=R7MGxLa7dAZfz5YbXMMPf6a6m8OcYZ2K&assertion=eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCIsImtpZCI6Imdua3AwMnUyIn0.eyJ0eXAiOiJqd3QiLCJraWQiOiJnbmtwMDJ1MiIsImlzcyI6Im9wNjNnMWFtY2hjeHk0NTZvZWkydGtmazFsZzRkYnh5IiwiYXVkIjoiaHR0cHM6XC9cL2FwaS5ib3guY29tXC9vYXV0aDJcL3Rva2VuIiwianRpIjoiNGYxZzIzYTEyYWE4NTRydHl1aWwiLCJleHAiOjE1MjIwODI5OTUsInN1YiI6IjIzNTI3MTg3IiwiYm94X3N1Yl90eXBlIjoiZW50ZXJwcmlzZSJ9.JMH1sXHrAsT9dURJF/5sOgl2k+qFX/wiqwER4RZwdtxLkLDXDJTzFGZuLPW8JMKqdzntc9hIdc/RHQOla2mi4s1WiGEj/9T1gBPWhjTd4kiZgEenLsZUuLFG77wlzdNPQnm3jON7kM08EfQZU+YYhGDF6JVJ2yH31zkJZqucdbg9Ne43OYPMKEmfa1bKJ3/QmLZXHIEgTYGhh78RsbzViJq3wCqWtUOmksDxCz7/400ZDrmQRH1JIEJW1W6A1oAjPEJVSTniw6a60VVTDXW3WUI0TN68CG5PuNzTXEJcBgnfr1J4yVWeat4rArEyOFsLoyOgBSIu0IHcMRo/V4Md4w==' -X POST
作为回应,我收到了这个错误
{"error":"invalid_grant","error_description":"Signature verification error. The public key identified by \"kid\" must correspond to the private key used for signing."}
连kid都给对了 我不知道我做错了什么
我已经使用 https://github.com/firebase/php-jwt 存储库解决了 Box JWT 令牌问题,并且工作正常。
use \Firebase\JWT\JWT;
class BoxApi
{
public $authorize_url = 'https://account.box.com/api/oauth2/authorize';
public $token_url = 'https://api.box.com/oauth2/token';
public $api_url = 'https://api.box.com/2.0';
public $upload_url = 'https://upload.box.com/api/2.0';
public $access_token;
public $filename;
public $passPhrase;
public $clientId;
public $clientSecret;
public $accessType;
public $accessTypeId;
public $publicKeyId;
public function __construct($filename, $passPhrase, $clientId, $clientSecret, $accessType = "enterprise", $accessTypeId, $publicKeyId)
{
$this->filename = $filename;
$this->passPhrase = $passPhrase;
$this->clientId = $clientId;
$this->clientSecret = $clientSecret;
$this->accessType = $accessType;
$this->accessTypeId = $accessTypeId;
$this->publicKeyId = $publicKeyId;
self::getAccessToken();
}
/* Get AccessToken by JWT*/
public function getAccessToken()
{
$private_key_file = $this->filename;
$fp = fopen ($private_key_file, "r");
if (!$fp)
{
die("Unable to open file");
}
$raw_key_data = fread ($fp, filesize ($private_key_file));
fclose ($fp);
$privateKey = openssl_get_privatekey($raw_key_data , $this->passPhrase);
define("FIREBASE_PRIVATE_KEY", $privateKey);
$token = array(
"iss" => $this->clientId,
"aud" => "https://api.box.com/oauth2/token",
"jti" => sprintf('%04x%04x-%04x-%04x-%04x-%04x%04x%04x',
mt_rand(0, 0xffff), mt_rand(0, 0xffff),
mt_rand(0, 0xffff),
mt_rand(0, 0x0fff) | 0x4000,
mt_rand(0, 0x3fff) | 0x8000,
mt_rand(0, 0xffff), mt_rand(0, 0xffff), mt_rand(0, 0xffff)
),
"exp" => time() + 30,
"sub" => $this->accessTypeId,
"box_sub_type" => $this->accessType
);
$jwt = JWT::encode($token, FIREBASE_PRIVATE_KEY, 'RS256', $this->publicKeyId);
$params = 'grant_type=urn:ietf:params:oauth:grant-type:jwt-bearer&client_id=' . $this->clientId . '&client_secret=' . $this->clientSecret . '&assertion=' . $jwt;
$token = json_decode(self::httpClient("POST", $this->token_url, $params), true);
print "<pre>";
print_r($token);
print "</pre>";
$this->access_token = $token["access_token"];
}
/* Sets the required before biulding the query */
private function set_opts(array $opts)
{
if (!array_key_exists('access_token', $opts)) {
$opts['access_token'] = $this->access_token;
}
return $opts;
}
/* Builds the URL for the call */
private function build_url($api_func, array $opts = array(), $url = null)
{
print "build uri";
$opts = $this->set_opts($opts);
if (isset($url)) {
$base = $url . $api_func . '?';
} else {
$base = $this->api_url . $api_func . '?';
}
$query_string = http_build_query($opts);
$base = $base . $query_string;
return $base;
}
/* Uploads a file */
public function put_file($filename, $parent_id)
{
$file = defined('PHP_MAJOR_VERSION') && PHP_MAJOR_VERSION >= 5 ? new CurlFile(realpath($filename)) : '@/' . realpath($filename);
$url = $this->build_url('/files/content', array(), $this->upload_url);
$params = array('filename' => $file, 'name' => basename($filename), 'parent_id' => $parent_id, 'access_token' => $this->access_token);
return json_decode($this->httpClient("post", $url, $params), true);
}
/* Create a new folder */
public function create_folder($name, $parent_id)
{
$url = $this->build_url("/folders");
$params = array('name' => $name, 'parent' => array('id' => $parent_id));
return json_decode($this->httpClient("post", $url, json_encode($params)), true);
}
/* Modifies the folder details as per the api */
public function update_folder($folder, array $params)
{
$url = $this->build_url("/folders/$folder");
return json_decode($this->httpClient("put", $url, $params), true);
}
/* Shares a folder */
public function share_folder($folder, array $params)
{
$url = $this->build_url("/folders/$folder");
return json_decode($this->httpClient("put", $url, $params), true);
}
/* Shares a file */
public function share_file($file, array $params)
{
$url = $this->build_url("/files/$file");
return json_decode($this->httpClient("put", $url, $params), true);
}
/* Curl Api calls */
private static function httpClient($method, $url, $params = null)
{
$ch = curl_init();
curl_setopt($ch, CURLOPT_URL, $url);
curl_setopt($ch, CURLOPT_RETURNTRANSFER, true);
curl_setopt($ch, CURLOPT_SSL_VERIFYPEER, false);
if (strcasecmp($method, "POST") == 0) {
curl_setopt($ch, CURLOPT_POST, true);
curl_setopt($ch, CURLOPT_POSTFIELDS, $params);
} elseif (strcasecmp($method, "PUT") == 0) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'PUT');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
} elseif (strcasecmp($method, "DELETE") == 0) {
curl_setopt($ch, CURLOPT_CUSTOMREQUEST, 'DELETE');
curl_setopt($ch, CURLOPT_POSTFIELDS, json_encode($params));
}
$data = curl_exec($ch);
curl_close($ch);
return $data;
}
}
?>