Ответ 1
Я не буду рекомендовать вам реализовать это самостоятельно, так как уже есть несколько библиотек, реализующих этот протокол. Однако я разделил свой ответ на 2 части, первая часть объясняет, как использовать пакет с открытым исходным кодом для решения вашей проблемы, вторая часть поможет вам, если вы хотите делать закрытые ключи.
Использование пакета
Есть несколько пакетов php, которые поддерживают подписание JWT, на момент написания того, который используется больше всего, это lcobucci/jwt, но есть и другие реализации, найденные здесь: https://packagist.org/search/?q=jwt
Вы можете использовать composer, чтобы установить его. Поскольку версия 4.0 не документирована прямо сейчас, я предлагаю вам установить 3.2 и посмотреть файл README этой версии.
Вы можете потребовать это в своем проекте, используя: composer require lcobucci/jwt:^3.2
В вашем примере кода вам понадобится RSA256, в библиотеке есть пример для этого:
<?php
use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Keychain; // just to make our life simpler
use Lcobucci\JWT\Signer\Rsa\Sha256; // you can use Lcobucci\JWT\Signer\Ecdsa\Sha256 if you're using ECDSA keys
$signer = new Sha256();
$keychain = new Keychain();
$token = (new Builder())
->setIssuer('http://example.com') // Configures the issuer (iss claim)
->setAudience('http://example.org') // Configures the audience (aud claim)
->setId('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
->setIssuedAt(time()) // Configures the time that the token was issue (iat claim)
->setNotBefore(time() + 60) // Configures the time that the token can be used (nbf claim)
->setExpiration(time() + 3600) // Configures the expiration time of the token (nbf claim)
->set('uid', 1) // Configures a new claim, called "uid"
->sign($signer, $keychain->getPrivateKey('file://{path to your private key}')) // creates a signature using your private key
->getToken(); // Retrieves the generated token
Подписание и проверка
При использовании открытых и закрытых ключей вы всегда должны быть уверены, что ваш секретный ключ будет безопасным. Однако вы можете легко публиковать свой открытый ключ в мире без ущерба для безопасности.
Подписание выполняется с использованием закрытого ключа, так как вы не хотите, чтобы люди могли подделывать вашу подпись, подписание с публичной частью сделало бы это возможным для всех. Это также означает, что шаг проверки всегда использует открытый ключ, потому что каждый должен иметь возможность сделать это.
Выполнение этого в PHP
Приведенный вами пример кода просто загружает закрытый ключ, но не выполняет никаких действий с ним. Для подписи вам нужно будет использовать openssl_sign
с вашей переменной. Resource #xx
просто означает ссылку на что-то внешнее в php.
<?php
// Data to sign
$payload = 'TEST';
// Generate a new key, load with: openssl_pkey_get_private
$privateKey = openssl_pkey_new(array('private_key_bits' => 512)); // NOT SECURE BUT FAST
// Extract public part from private key
$details = openssl_pkey_get_details($privateKey);
// Use openssl_pkey_get_public to load from file
$publicKey = $details['key'];
// Generated by openssl_sign
$signature = null;
// Sign with private key
openssl_sign($payload, $signature, $privateKey, OPENSSL_ALGO_SHA256);
// Use base64 because the signature contains binairy data
echo 'Signed data: '.base64_encode($signature).PHP_EOL;
// Use publicKey to verify signature
$valid = openssl_verify($payload, $signature, $publicKey, OPENSSL_ALGO_SHA256);
echo 'Signature is '.($valid ? 'Valid' : 'Invalid').PHP_EOL;
Что еще
Если вы все еще хотите реализовать полный протокол, я предлагаю вам еще раз взглянуть на пакет. И, как уже было предложено в комментариях, полная спецификация:
https://www.rfc-editor.org/rfc/rfc7519.txt
Последний совет: JWT использует несколько разных символов для base64, чем php, поэтому не забудьте правильно это обработать.