lake / larke-jwt
一个用于处理JSON Web Token和JSON Web Signature的库。
1.3.0
2024-03-14 04:32 UTC
Requires
- php: ~8.1 || ~8.2 || ~8.3
- ext-hash: *
- ext-json: *
- ext-mbstring: *
- ext-openssl: *
- ext-sodium: *
README
一个用于处理JSON Web Token和JSON Web Signature的简单库(需要PHP 5.6+)。实现基于RFC 7519。
代码是从lcobucci/jwt分叉而来
安装
您可以使用Composer进行安装。
composer require lake/larke-jwt
依赖
- PHP >= 8.1.0
- OpenSSL扩展
- sodium扩展
基本用法
创建
只需使用构建器创建新的JWT/JWS令牌
use DateTimeImmutable; use Larke\JWT\Builder; use Larke\JWT\Signer\None; use Larke\JWT\Signer\Key\InMemory; $now = new DateTimeImmutable(); $signer = new None(); $key = InMemory::plainText('testing') $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($now) // Configures the time that the token was issue (iat claim) ->canOnlyBeUsedAfter($now->modify('+1 minute')) // Configures the time that the token can be used (nbf claim) ->expiresAt($now->modify('+1 hour')) // Configures the expiration time of the token (exp claim) ->withClaim('uid', 1) // Configures a new claim, called "uid" ->getToken($signer, $key); // Retrieves the generated token $token->headers()->all(); // Retrieves the token headers $token->claims()->all(); // Retrieves the token claims echo $token->headers()->get('jti'); // will print "4f1g23a12aa" echo $token->claims()->get('iss'); // will print "http://example.com" echo $token->claims()->get('uid'); // will print "1" echo $token->toString(); // The string representation of the object is a JWT string (pretty easy, right?)
从字符串解析
使用解析器从JWT字符串创建新的令牌(使用之前的令牌作为示例)
use Larke\JWT\Parser; $token = (new Parser())->parse((string) $token); // Parses from a string $token->headers()->all(); // Retrieves the token headers $token->claims()->all(); // Retrieves the token claims echo $token->headers()->get('jti'); // will print "4f1g23a12aa" echo $token->claims()->get('iss'); // will print "http://example.com" echo $token->claims()->get('uid'); // will print "1"
验证
我们可以轻松地验证令牌是否有效(使用之前的令牌和时间作为示例)
use DateTimeImmutable; use Larke\JWT\Validator; use Larke\JWT\ValidationData; $now = new DateTimeImmutable(); $data = new ValidationData(); // It will use the current time to validate (iat, nbf and exp) $data->issuedBy('http://example.com'); $data->permittedFor('http://example.org'); $data->identifiedBy('4f1g23a12aa'); $validation = new Validator(); var_dump($validation->validate($token, $data)); // false, because token cannot be used before now() + 60 $data->currentTime($now->modify('+61 seconds')); // changing the validation time to future var_dump($validation->validate($token, $data)); // true, because current time is between "nbf" and "exp" claims $data->currentTime($now->modify('+4000 seconds')); // changing the validation time to future var_dump($validation->validate($token, $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 now is invalid but the difference between that and the validation time is less than $leeway, // then token is still considered valid $dataWithLeeway = new ValidationData($now, 20); $dataWithLeeway->issuedBy('http://example.com'); $dataWithLeeway->permittedFor('http://example.org'); $dataWithLeeway->identifiedBy('4f1g23a12aa'); var_dump($validation->validate($token, $dataWithLeeway)); // false, because token can't be used before now() + 60, not within leeway $dataWithLeeway->currentTime($now->modify('+51 seconds')); // changing the validation time to future var_dump($validation->validate($token, $dataWithLeeway)); // true, because current time plus leeway is between "nbf" and "exp" claims $dataWithLeeway->currentTime($now->modify('+3610 seconds')); // changing the validation time to future but within leeway var_dump($validation->validate($token, $dataWithLeeway)); // true, because current time - 20 seconds leeway is less than exp $dataWithLeeway->currentTime($now->modify('+4000 seconds')); // changing the validation time to future outside of leeway var_dump($validation->validate($token, $dataWithLeeway)); // false, because token is expired since current time is greater than exp
重要
- 您必须配置
ValidationData
来告知所有要验证的声明。 - 如果
ValidationData
包含未在令牌中使用的声明或令牌包含在ValidationData
中未配置的声明,则它们将由Token::validate()
忽略。 exp
、nbf
和iat
声明默认在ValidationData::__construct()
中配置为当前时间(DateTimeImmutable
)。ValidationData
的可选$leeway
参数将在验证基于时间的声明时使用该数量的秒数。对于“已发行”(iat
)和“不在之前”(nbf
)声明,它假装我们处于未来;对于“过期时间”(exp
)声明,它假装我们处于过去。这允许出现发布服务器和验证服务器时钟不同的场景,如RFC 7519第4.1节中所述。
令牌签名
我们可以使用签名来验证令牌在生成后是否被修改。此库实现了Hmac
、RSA
、ECDSA
、EdDSA
和Blake2b
签名(使用256、384和512位)。none
不是签名。
重要
不要允许发送到解析器的字符串决定要使用哪种签名算法,否则您的应用程序将容易受到关键的JWT安全漏洞的影响。
下面的示例是安全的,因为Signer
的选择是硬编码的,不能被恶意用户影响。
Hmac和Blake2b
Hmac签名非常简单易用
use DateTimeImmutable; use Larke\JWT\Builder; use Larke\JWT\Validator; use Larke\JWT\Signer\Hmac\Sha256; use Larke\JWT\Signer\Key\InMemory; $now = new DateTimeImmutable(); $signer = new Sha256(); $key = InMemory::plainText('testing'); $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($now) // Configures the time that the token was issue (iat claim) ->canOnlyBeUsedAfter($now->modify('+1 minute')) // Configures the time that the token can be used (nbf claim) ->expiresAt($now->modify('+1 hour')) // Configures the expiration time of the token (exp claim) ->withClaim('uid', 1) // Configures a new claim, called "uid" ->getToken($signer, $key); // Retrieves the generated token $key1 = InMemory::plainText('testing 1'); $key2 = InMemory::plainText('testing'); $validation = new Validator(); var_dump($validation->verify($token, $signer, $key1)); // false, because the key is different var_dump($validation->verify($token, $signer, $key2)); // true, because the key is the same
RSA、ECDSA和EdDSA
RSA、ECDSA和EdDSA签名基于公钥和私钥,因此您必须使用私钥生成并使用公钥验证
use DateTimeImmutable; use Larke\JWT\Builder; use Larke\JWT\Validator; use Larke\JWT\Signer\Key\LocalFileReference; use Larke\JWT\Signer\Rsa\Sha256; // you can use Larke\JWT\Signer\Ecdsa\Sha256 if you're using ECDSA keys $now = new DateTimeImmutable(); $signer = new Sha256(); $privateKey = LocalFileReference::file('file://{path to your private key}'); $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($now) // Configures the time that the token was issue (iat claim) ->canOnlyBeUsedAfter($now->modify('+1 minute')) // Configures the time that the token can be used (nbf claim) ->expiresAt($now->modify('+1 hour')) // 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 = LocalFileReference::file('file://{path to your public key}'); $validation = new Validator(); var_dump($validation->verify($token, $signer, $publicKey)); // true when the public key was generated by the private one =)
重要的是要说明,如果您使用RSA密钥,则不应调用ECDSA签名者(反之亦然),否则sign()
和verify()
将引发异常!