timjmasters / php-jws
一些用于创建和解码JWS令牌的工具
0.5
2021-11-05 04:30 UTC
Requires
- php: ^7.2|^8.0
- timjmasters/php-base64url: ^1.0
Requires (Dev)
- php-coveralls/php-coveralls: ^2.4
- phpunit/phpunit: ^9.0
This package is auto-updated.
Last update: 2024-09-05 10:43:20 UTC
README
php-jws
PHP的一些JWS工具 - 由Timothy John Masters编写
这段代码更多的是作为一个学习/练习的练习,firebase/php-jwt 可能会更完整,功能更丰富。
目前仅支持无序列化JWS compact,没有实施JWS JSON序列化解决方案的意图。
安装
使用composer作为依赖项安装,然后使用composer自动加载器:composer require timjmasters/php-jws
用法
使用JWSUtil类创建和验证JWS令牌。
JWSUtil - 用于创建和验证JWS对象的实用类
JWSUtil::createFromPayload($payload, array $options) : JWS
使用指定的有效负载和选项创建JWS对象,包括编码部分和签名令牌- header:设置您需要的任何标题字段,默认为
["alg" => "HS256", "typ" => "JWT"]
(见下文,了解支持算法) - payload:有关有效负载的选项数组
- encoding:可以是
json_encoding
或as_string
(默认:json_encoding)如果使用json_encoding
,则将在设置对象之前将有效负载JSON编码,因此对象的getPayload()方法将返回JSON编码的字符串,除非提供了json_decode参数。如果使用as_string
,则将在设置对象之前将有效负载转换为字符串。 - encoding_options:传递给json_encode函数的选项,例如JSON_PRETTY_PRINT(默认:0)
- encoding:可以是
- secret:用于创建签名的密钥或密钥
- header:设置您需要的任何标题字段,默认为
JWSUtil::createFromEncoded(string $token, bool $json_decode) : JWS
从编码的JWS字符串创建JWS对象,如果$json_decode参数为true,则在设置之前将有效负载解码,如果无法解码有效负载,则抛出异常。签名设置为提供的签名,因此请确保在信任令牌之前验证令牌。JWSUtil::verify(JWS $jws, $secret, array $allowed_algorithms)
验证JWS令牌的签名是否与其内容匹配。如果令牌签名未验证,则返回false。- 标题的算法不在提供的允许算法中(默认:["HS256", "RS256"])
- 如果是HMAC
- 使用提供的密钥将base64url编码的json编码的标题与单个句点连接,并与base64url编码的有效负载(在创建令牌时可选地进行了json编码)进行哈希,并将结果与令牌的签名进行比较
- 如果是RSA
- 使用openssl_verify函数验证令牌的签名是否有效,对于base64url编码的json编码的标题与单个句点连接,并与base64url编码的有效负载(在创建令牌时可选地进行了json编码)
- 应在$secret参数中提供公钥,它可以是字符串或使用openssl函数创建的资源标识符。
JWS
该对象具有用于查看令牌中编码的数据的方法。不建议您直接使用设置器,而是使用JWSUtil类创建令牌。
$jws->getHeader()
- 获取标题作为数组,通常类似于['alg' => 'RS256', 'typ' => 'JWT']
$jws->getPayload($json_decode = false)
- 获取有效负载,可选的json_decode参数是一种方便,以防在创建令牌时未对有效负载进行编码(即使用'as_string'编码选项,但仍然是有效的json,您希望解码)。
- 负载不一定是json字符串或数组,它可以是二进制数据
$jws->getSignature()
- 获取未编码的签名,通常是一个哈希或二进制字符串
$jws->getHeaderEncoded()
- 获取JWS头部作为base64url编码的json编码字符串
$jws->getPayloadEncoded()
- 获取负载base64url编码
- 当设置时,负载可以可选地进行编码
$jws->getSignatureEncoded()
- 获取签名base64url编码
$jws->getEncoded()
- 获取所有编码部分,用点连接。例如:eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.WUphQgEfGvtdUCw4UntIh__bemKY6eDFjX2K2XCZP
- 相当于
$jws->getHeaderEncoded() . '.' . $jws->getPayloadEncoded() . '.' . $jws->getSignatureEncoded
$jws->setHeader(array $header)
- 设置JWS头部
- 编码值将更新,如果头部已更改,签名将不匹配
$jws->setPayload($payload, $json_encode = false)
- 设置负载,可选地将其编码为json字符串
- 编码值将更新,如果负载已更改,签名将不匹配
$jws->setSignature($signature)
- 设置签名
- 不会与头部和负载进行比较,不建议直接使用此方法
注意事项
当前支持算法
- HS256
- HMAC SHA 256 - JWS令牌将使用秘密选项进行签名
- RS256
- RSA SHA 256 - JWS令牌将假设秘密选项是私钥进行签名
示例
从数组创建JWS对象,json编码它
use TimJMasters\JWS\JWSUtil; $jws = JWSUtil::createFromPayload( // The payload [ "foo" => "bar" ], [ "secret" => "foobar123", "payload" => [ "encoding" => JWSUtil::PAYLOAD_AS_JSON //"json_encode" ] ] ); print $jws . "\r\n"; // Will output eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.U_rA2byM9Nw_zrXNZfAqEOuyqCO75B9iHh6yO-Fjjgg // You can also get the header or payload as an array using the $jws->getHeader() or $jws->getPayload() methods.
使用RS256创建JWS对象
use TimJMasters\JWS\JWSUtil; $private_key = openssl_pkey_get_private("path/to/your/private/key.pem"); $public_key = openssl_pkey_get_public("path/to/your/public/key.pem"); // Or you could do: // $private_key = file_get_contents("path/to/your/private/key.pem"); // $public_key = file_get_contents("path/to/your/public/key.pem"); // Options for creating the token $options = [ "header" => [ "alg" => JWSUtil::RSA_SHA256, // 'RS256' "typ" => "JWT", ], "secret" => $private_key, ]; // Create the token $jws = JWSUtil::createFromPayload(["foo" => "bar"], $options); print $jws; // eyJhbGciOiJSUzI1NiIsInR5cCI6IkpXVCJ9.eyJmb28iOiJiYXIifQ.SIGNATURE_ACCORDING_TO_YOUR_CERTIFICATES var_export(JWSUtil::verify($jws, $public_key, ["RS256"])); // true
验证来自Google的令牌
use TimJMasters\JWS\JWSUtil; // Assuming we have a token from google we can create a JWS object $id_token = JWSUtil::createFromEncoded($google_token); // Make sure you follow verification according to https://developers.google.com/identity/protocols/oauth2/openid-connect#validatinganidtoken as the library only checks the signature. // Get the key location from the jwks_uri in the Discovery document, use an HTTP library or curl to make the requests to Google. $jwks_uri = json_decode(http_get_request('https://#/.well-known/openid-configuration'), true)['jwsk_uri']; // Currently https://www.googleapis.com/oauth2/v3/certs as of 2021/03/04 $google_keys = json_decode(http_get_request($jwks_uri), true); // Gives an array of keys // Search the array for the correct kid according to the value in the token header $key_info = array_search($idToken->getHeader()['kid'], array_column($google_keys, "kid")); // You should probably check the key algorithm matches the token algorithm, but I won't show that here as using the $key_info['alg'] value as the only allowed algorithm effectively does that. // Google currently uses RSA keys, you need to get the public key based on the modulus and exponent provided. // I won't show how to do this here, but you might use the phpseclib library, or the firebase/php-jwt source as a way of calculating it here: https://github.com/firebase/php-jwt/blob/f42c9110abe98dd6cfe9053c49bc86acc70b2d23/src/JWK.php#L116 $public_key = createKeyFrom($key_info["n"], $key_info["e"]); var_export(JWSUtil::verify($id_token, $public_key, [$key_info['alg']])); // Prints true or false