qeq66/jwt

一个用于处理 JSON Web Token 和 JSON Web Signature 的简单库

维护者

详细信息

github.com/qeq66/jwt

源代码

4.1.5 2021-09-28 19:34 UTC

README

Gitter Total Downloads Latest Stable Version

Branch master Build Status Scrutinizer Code Quality Code Coverage

一个用于处理 JSON Web Token 和 JSON Web Signature 的简单库(需要 PHP 5.6+)。实现基于RFC 7519

安装

该包在Packagist上可用,您可以使用Composer安装它。

composer require lcobucci/jwt

依赖项

  • PHP 5.6+
  • OpenSSL 扩展

基本用法

创建

只需使用构建器创建新的 JWT/JWS 令牌

use Lcobucci\JWT\Builder;

$time = time();
$token = (new Builder())->issuedBy('http://example.com') // Configures the issuer (iss claim)
                        ->permittedFor('http://example.org') // Configures the audience (aud claim)
                        ->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
                        ->issuedAt($time) // Configures the time that the token was issue (iat claim)
                        ->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)
                        ->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
                        ->withClaim('uid', 1) // Configures a new claim, called "uid"
                        ->getToken(); // Retrieves the generated token


$token->getHeaders(); // Retrieves the token headers
$token->getClaims(); // Retrieves the token claims

echo $token->getHeader('jti'); // will print "4f1g23a12aa"
echo $token->getClaim('iss'); // will print "http://example.com"
echo $token->getClaim('uid'); // will print "1"
echo $token; // The string representation of the object is a JWT string (pretty easy, right?)

从字符串解析

使用解析器从 JWT 字符串创建新的令牌(使用之前的令牌作为示例)

use Lcobucci\JWT\Parser;

$token = (new Parser())->parse((string) $token); // Parses from a string
$token->getHeaders(); // Retrieves the token header
$token->getClaims(); // Retrieves the token claims

echo $token->getHeader('jti'); // will print "4f1g23a12aa"
echo $token->getClaim('iss'); // will print "http://example.com"
echo $token->getClaim('uid'); // will print "1"

验证

我们可以轻松验证令牌是否有效(使用之前的令牌和时间作为示例)

use Lcobucci\JWT\ValidationData;

$data = new ValidationData(); // It will use the current time to validate (iat, nbf and exp)
$data->setIssuer('http://example.com');
$data->setAudience('http://example.org');
$data->setId('4f1g23a12aa');

var_dump($token->validate($data)); // false, because token cannot be used before now() + 60

$data->setCurrentTime($time + 61); // changing the validation time to future

var_dump($token->validate($data)); // true, because current time is between "nbf" and "exp" claims

$data->setCurrentTime($time + 4000); // changing the validation time to future

var_dump($token->validate($data)); // false, because token is expired since current time is greater than exp

// We can also use the $leeway parameter to deal with clock skew (see notes below)
// If token's claimed time is invalid but the difference between that and the validation time is less than $leeway, 
// then token is still considered valid
$dataWithLeeway = new ValidationData($time, 20); 
$dataWithLeeway->setIssuer('http://example.com');
$dataWithLeeway->setAudience('http://example.org');
$dataWithLeeway->setId('4f1g23a12aa');

var_dump($token->validate($dataWithLeeway)); // false, because token can't be used before now() + 60, not within leeway

$dataWithLeeway->setCurrentTime($time + 51); // changing the validation time to future

var_dump($token->validate($dataWithLeeway)); // true, because current time plus leeway is between "nbf" and "exp" claims

$dataWithLeeway->setCurrentTime($time + 3610); // changing the validation time to future but within leeway

var_dump($token->validate($dataWithLeeway)); // true, because current time - 20 seconds leeway is less than exp

$dataWithLeeway->setCurrentTime($time + 4000); // changing the validation time to future outside of leeway

var_dump($token->validate($dataWithLeeway)); // false, because token is expired since current time is greater than exp

重要

  • 您必须配置 ValidationData 以告知所有要验证的声明。
  • 如果 ValidationData 包含未在令牌中使用的声明或令牌包含未在 ValidationData 中配置的声明,则它们将被 Token::validate() 忽略。
  • expnbfiat 声明默认在 ValidationData::__construct() 中配置为当前 UNIX 时间(time())。
  • ValidationData 的可选 $leeway 参数将在验证基于时间的声明时使用该数量的秒数。对于 "发行时间"(《iat》)和 "在此之前"(《nbf》)声明,我们假装它们在将来;对于 "过期时间"(《exp》)声明,我们假装它们在过去。这允许出现发行服务器和验证服务器时钟不同的情况,如RFC 7519第4.1节所述。

令牌签名

我们可以使用签名来验证令牌在生成后是否未被修改。此库实现了 Hmac、RSA 和 ECDSA 签名(使用 256、384 和 512)。

重要

不要允许发送给解析器的字符串指定要使用的签名算法,否则您的应用程序将容易受到关键的 JWT 安全漏洞的攻击。

下面的示例是安全的,因为 Signer 的选择是硬编码的,不能被恶意用户影响。

Hmac

Hmac 签名非常简单易用

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Hmac\Sha256;

$signer = new Sha256();
$time = time();

$token = (new Builder())->issuedBy('http://example.com') // Configures the issuer (iss claim)
                        ->permittedFor('http://example.org') // Configures the audience (aud claim)
                        ->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
                        ->issuedAt($time) // Configures the time that the token was issue (iat claim)
                        ->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)
                        ->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
                        ->withClaim('uid', 1) // Configures a new claim, called "uid"
                        ->getToken($signer, new Key('testing')); // Retrieves the generated token


var_dump($token->verify($signer, 'testing 1')); // false, because the key is different
var_dump($token->verify($signer, 'testing')); // true, because the key is the same

RSA 和 ECDSA

RSA 和 ECDSA 签名基于公钥和私钥,因此您必须使用私钥生成并使用公钥验证

use Lcobucci\JWT\Builder;
use Lcobucci\JWT\Signer\Key;
use Lcobucci\JWT\Signer\Rsa\Sha256; // you can use Lcobucci\JWT\Signer\Ecdsa\Sha256 if you're using ECDSA keys

$signer = new Sha256();
$privateKey = new Key('file://{path to your private key}');
$time = time();

$token = (new Builder())->issuedBy('http://example.com') // Configures the issuer (iss claim)
                        ->permittedFor('http://example.org') // Configures the audience (aud claim)
                        ->identifiedBy('4f1g23a12aa', true) // Configures the id (jti claim), replicating as a header item
                        ->issuedAt($time) // Configures the time that the token was issue (iat claim)
                        ->canOnlyBeUsedAfter($time + 60) // Configures the time that the token can be used (nbf claim)
                        ->expiresAt($time + 3600) // Configures the expiration time of the token (exp claim)
                        ->withClaim('uid', 1) // Configures a new claim, called "uid"
                        ->getToken($signer,  $privateKey); // Retrieves the generated token

$publicKey = new Key('file://{path to your public key}');

var_dump($token->verify($signer, $publicKey)); // true when the public key was generated by the private one =)

重要的是要说,如果您正在使用 RSA 密钥,则不应调用 ECDSA 签名者(反之亦然),否则 sign()verify() 将引发异常!