不使用第三方库的PHP中的JWT(JSON Web Token)。怎么签?

时间:2015-11-18 06:47:15

标签: php json authentication jwt sha

有一些用于在PHP中实现JSON Web令牌(JWT)的库,例如php-jwt。我正在编写自己的,非常小而简单的类,但无法弄清楚为什么我的签名未通过验证here,尽管我已经尝试坚持标准。我已经尝试了几个小时而且我被卡住了。请帮忙!

我的代码很简单

//build the headers
$headers = ['alg'=>'HS256','typ'=>'JWT'];
$headers_encoded = base64url_encode(json_encode($headers));

//build the payload
$payload = ['sub'=>'1234567890','name'=>'John Doe', 'admin'=>true];
$payload_encoded = base64url_encode(json_encode($payload));

//build the signature
$key = 'secret';
$signature = hash_hmac('SHA256',"$headers_encoded.$payload_encoded",$key);

//build and return the token
$token = "$headers_encoded.$payload_encoded.$signature";
echo $token;

base64url_encode功能:

function base64url_encode($data) {
    return rtrim(strtr(base64_encode($data), '+/', '-_'), '=');
}

我的标头和有效负载与validation site's默认JWT完全匹配,但我的签名不匹配,因此我的令牌被标记为无效。这个标准看起来很简单,所以我的签名有什么问题?

2 个答案:

答案 0 :(得分:15)

我解决了!我没有意识到签名本身需要base64编码。另外,我需要将hash_hmac函数的最后一个可选参数设置为$raw_output=true(请参阅the docs。简而言之,我需要更改原始代码:

//build the signature
$key = 'secret';
$signature = hash_hmac('SHA256',"$headers_encoded.$payload_encoded",$key);

//build and return the token
$token = "$headers_encoded.$payload_encoded.$signature";

纠正:

//build the signature
$key = 'secret';
$signature = hash_hmac('SHA256',"$headers_encoded.$payload_encoded",$key,true);
$signature_encoded = base64url_encode($signature);

//build and return the token
$token = "$headers_encoded.$payload_encoded.$signature_encoded";
echo $token;

答案 1 :(得分:0)

如果要使用 RS256 (而不是像OP那样的HS256)来解决它,可以这样使用:

//build the headers
$headers = ['alg'=>'RS256','typ'=>'JWT'];
$headers_encoded = base64url_encode(json_encode($headers));

//build the payload
$payload = ['sub'=>'1234567890','name'=>'John Doe', 'admin'=>true];
$payload_encoded = base64url_encode(json_encode($payload));

//build the signature
$key = "-----BEGIN PRIVATE KEY----- ....";
openssl_sign("$headers_encoded.$payload_encoded", $signature, $key, 'sha256WithRSAEncryption'); 
$signature_encoded = base64url_encode($signature);

//build and return the token
$token = "$headers_encoded.$payload_encoded.$signature_encoded";
echo $token;

把我带走的时间比我承认的时间长