rbdwllr / reallysimplejwt
一个用于生成用户认证JSON Web Tokens的简单库。
Requires
- php: >=8.0.0
Requires (Dev)
- friendsofphp/php-cs-fixer: ^2.19
- infection/infection: ^0.26
- phpbench/phpbench: ^1.2
- phploc/phploc: ^7.0
- phpmd/phpmd: ^2.11
- phpstan/phpstan: ^1.2
- phpunit/phpunit: ^9.5
- sebastian/phpcpd: ^6.0
- squizlabs/php_codesniffer: ^3.6
- dev-master
- 5.0.0
- 5.0.0-rc
- 5.0.0-beta
- 4.x-dev
- 4.0.3
- 4.0.2
- 4.0.1
- 4.0.0
- 4.0.0-rc
- 4.0.0-beta
- 4.0.0-alpha
- 3.x-dev
- 3.1.2
- 3.1.1
- 3.1.0
- 3.0.3
- 3.0.2
- 3.0.1
- 3.0.0
- 3.0.0-rc
- 3.0.0-beta
- 2.1.0
- 2.0.5
- 2.0.4
- 2.0.3
- 2.0.2
- 2.0.1
- 2.0.0
- 2.0.0-rc1
- 2.0.0-rc
- 2.0.0-beta
- 2.0.0-alpha1
- 2.0.0-alpha
- 1.1.0
- 1.0.6
- 1.0.5
- 1.0.4
- 1.0.3
- 1.0.2
- 1.0.1
- 1.0.0
- 0.2
- 0.2-alpha1
- 0.2-alpha
- 0.1
- 0.1-beta
- v0.1-alpha1
- v0.1-alpha
This package is auto-updated.
Last update: 2024-09-17 18:32:12 UTC
README
这是一个简单的PHP库,用于创建使用HMAC SHA256进行签名的JSON Web Tokens。对于基本使用,库公开了一个静态接口,允许开发者创建一个存储用户标识和过期时间的令牌。
该库也支持扩展,开发者可以定义自己的编码和密钥标准,设置所有RFC标准 JWT声明,并设置自己的私有声明。
你可以轻松地将ReallySimpleJWT与PSR-7 / PSR-15兼容的框架,如Slim PHP,通过PSR-JWT中间件库进行集成。请阅读框架集成文档以了解更多信息。
如果你需要在浏览器中读取令牌,请查看我们的JavaScript / TypeScript库RS-JWT。
内容
什么是JSON Web Token?
JSON Web Tokens是一种创建关于用户或系统的声明的URL友好访问令牌的标准。
令牌分为三部分;头部、有效载荷和签名;各部分之间由点分隔。每一部分都使用base64URL标准进行编码,请参阅RFC。
一个JWT示例
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
头部和有效载荷都是包含多个声明的编码JSON字符串
// Example Header { "alg": "HS256", "typ": "JWT" } // Example Payload { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
声明是一个键值对,例如"typ": "JWT"
,请阅读RFC 7519以了解更多关于JSON Web Token声明的信息。
通过签名实现令牌安全,签名由头部、有效载荷和只有令牌作者知道的密钥组成。这些信息被散列然后进行base64URL编码。
如果恶意用户尝试编辑头部或有效载荷声明,只要使用强大的密钥,他们将无法复制签名。请参阅令牌安全以了解更多信息。
设置
要安装此包,您需要安装Composer,然后运行composer init
。完成此操作后,您可以通过命令行或通过编辑由composer init
命令创建的composer.json文件来安装包。
最后,您需要在PHP代码中引用Composer自动加载器,require 'vendor/autoload.php';
。自动加载文件的位置取决于您的代码在哪里运行,如果您使用的是框架,可能不需要它。
通过命令行使用Composer安装
composer require rbdwllr/reallysimplejwt
通过composer.json文件安装
将以下内容添加到您的composer.json文件中
"require": { "rbdwllr/reallysimplejwt": "^5.0" }
然后运行
composer update
基本使用
对于基本使用,该库通过ReallySimpleJWT\Token
类公开了一组静态方法,允许开发人员创建和验证基本的JSON Web Tokens。
创建令牌
调用create()
静态方法,传入用户标识符、密钥、过期日期时间数字和令牌发行者。
如果成功,这将返回一个令牌字符串,如果失败,将抛出ReallySimpleJWT\Exception\BuildException
。
use ReallySimpleJWT\Token; $userId = 12; $secret = 'sec!ReT423*&'; $expiration = time() + 3600; $issuer = 'localhost'; $token = Token::create($userId, $secret, $expiration, $issuer);
要创建更自定义的令牌,开发者可以使用customPayload()
方法。这允许根据表示有效载荷声明的键值对数组创建令牌。
use ReallySimpleJWT\Token; $payload = [ 'iat' => time(), 'uid' => 1, 'exp' => time() + 10, 'iss' => 'localhost' ]; $secret = 'Hello&MikeFooBar123'; $token = Token::customPayload($payload, $secret);
如果成功,customPayload()
方法将返回JWT令牌字符串,如果失败将抛出异常。
验证令牌
要验证JSON Web Token,调用validate()
静态方法,传入令牌字符串和密钥。验证方法检查令牌结构是否正确,签名是否有效。
如果成功返回true,如果失败返回false。
use ReallySimpleJWT\Token; $token = 'aaa.bbb.ccc'; $secret = 'sec!ReT423*&'; $result = Token::validate($token, $secret);
还有可用于验证令牌的过期声明和不可用声明的其他方法。两者在成功时都返回true,失败时返回false。
use ReallySimpleJWT\Token; $token = 'aaa.bbb.ccc'; Token::validateExpiration($token); Token::validateNotBefore($token);
获取头部和有效载荷声明数据
要从头部或有效载荷检索令牌声明数据,请调用getHeader()
和/或getPayload()
静态方法。
这两种方法在成功时都返回关联数组,在失败时抛出异常。
use ReallySimpleJWT\Token; $token = 'aaa.bbb.ccc'; // Return the header claims Token::getHeader($token); // Return the payload claims Token::getPayload($token);
构建、解析和验证工厂方法
ReallySimpleJWT\Token
类还提供了三个工厂方法,用于访问核心的ReallySimpleJWT\Build
、ReallySimpleJWT\Parse
和ReallySimpleJWT\Validate
类。这些类允许您根据需要构建自定义令牌,并解析和验证令牌。
Token::builder(); // Returns an instance of ReallySimpleJWT\Build Token::parser($token); // Returns an instance of ReallySimpleJWT\Parse Token::validator($token, $secret); // Returns an instance of ReallySimpleJWT\Validate
非静态使用
ReallySimpleJWT\Token
类是ReallySimpleJWT\Tokens
类的包装器,对于那些更喜欢实例化和注入功能的人来说,可以直接使用。
use ReallySimpleJWT\Tokens; $tokens = new Tokens(); $id = 52; $secret = 'sec!ReT423*&'; $expiration = time() + 50; $issuer = 'localhost'; $token = $tokens->create('id', $id, $secret, $expiration, $issuer); $token->getToken();
请注意,当在Tokens
类上调用create()
和customPayload()
方法时,它们将返回Jwt
类的一个实例,而Token
类将返回一个令牌字符串。
此外,create()
方法与Tokens
类的签名略有不同,因为必须传入用户标识符键。
create(string $userKey, $userId, string $secret, int $expiration, string $issuer): Jwt
高级使用
要创建自定义的JSON Web Tokens,开发者需要直接访问ReallySimpleJWT\Build
、ReallySimpleJWT\Parse
和ReallySimpleJWT\Validate
类。
创建自定义令牌
ReallySimpleJWT\Build
类允许您创建一个完全独特的JSON Web Token。它提供了所有RFC定义的头部和有效载荷声明的辅助方法。例如,setIssuer()
方法将添加iss
声明到令牌有效载荷中。
该类还允许开发者通过setHeaderClaim()
和setPayloadClaim()
方法设置自定义头部和有效载荷声明。
可以将这些方法链接在一起,当调用build()
方法时,将生成并返回一个ReallySimpleJWT\Jwt
对象。
use ReallySimpleJWT\Build; use ReallySimpleJWT\Helper\Validator; use ReallySimpleJWT\Encoders\EncodeHS256; $secret = '!secReT$123*'; $build = new Build('JWT', new Validator(), new EncodeHS256($secret)); $token = $build->setContentType('JWT') ->setHeaderClaim('info', 'foo') ->setIssuer('localhost') ->setSubject('admins') ->setAudience('https://google.com') ->setExpiration(time() + 30) ->setNotBefore(time() - 30) ->setIssuedAt(time()) ->setJwtId('123ABC') ->setPayloadClaim('uid', 12) ->build();
访问令牌
当开发者在ReallySimpleJWT\Build
类上调用build()
方法时,将返回一个ReallySimpleJWT\Jwt
对象。Jwt类提供了一个getToken()
方法,用于返回令牌字符串。
要通过ReallySimpleJWT\Parse
类解析JSON Web Token,开发者必须首先通过实例化时注入令牌字符串来创建一个新的ReallySimpleJWT\Jwt
对象。Jwt类将在实例化时验证令牌结构以确保完整性。
use ReallySimpleJWT\Jwt; $token = 'aaa.bbb.ccc'; $jwt = new Jwt($token); // Return the token $jwt->getToken();
解析令牌
ReallySimpleJWT\Parse
类允许开发者解析JWT,parse()
方法将解码JSON Web Token,并将结果作为ReallySimpleJWT\Parsed
对象返回。这将提供对令牌持有的头部和有效载荷声明数据的访问。
use ReallySimpleJWT\Parse; use ReallySimpleJWT\Jwt; use ReallySimpleJWT\Decode; $token = 'aaa.bbb.ccc'; $jwt = new Jwt($token); $parse = new Parse($jwt, new Decode()); $parsed = $parse->parse(); // Return the token header claims as an associative array. $parsed->getHeader(); // Return the token payload claims as an associative array. $parsed->getPayload();
访问令牌声明数据
当开发者调用 ReallySimpleJWT\Parse
类的 parse()
方法时,将返回 ReallySimpleJWT\Parsed
类。
它提供了一些辅助方法来访问令牌声明数据。开发者可以通过调用 getHeader()
和 getPayload()
方法来获取相应的声明数据作为关联数组。
开发者还可以调用RFC 兼容的声明方法之一
头部
getAlgorithm()
getType()
getContentType()
载荷
getIssuer()
getSubject()
getAudience()
getExpiration()
getNotBefore()
getIssuedAt()
getJwtId()
getExpiresIn()
getUsableIn()
令牌验证方法
要验证 JSON Web Token,开发者可以使用 ReallySimpleJWT\Validate
类。要使用验证类,需要创建并注入一个 ReallySimpleJWT\Parsed
对象。这样验证类就可以访问令牌中的信息。
use ReallySimpleJWT\Jwt; use ReallySimpleJWT\Parse; use ReallySimpleJWT\Validate; use ReallySimpleJwt\Decode; use ReallySimpleJwt\Encoders\EncodeHS256; use ReallySimpleJwt\Helper\Validator; $token = new Jwt('abc.def.ghi'); $parse = new Parse($jwt, new Decode()); $parsed = $parse->parse(); $validate = new Validate( $parsed, new EncodeHS256(), new Validator() ); $validate->signature();
有六个验证方法可用,都可以串联使用
signature()
确认令牌签名是有效的。expiration()
确认令牌过期声明(exp
)尚未过期。notBefore()
确认令牌不早于声明(nbf
)已过期。audience()
确认令牌受众声明(aud
)与预期匹配。algorithm()
确认令牌算法声明(alg
)与预期匹配且有效(参见:RFC 7518)。algorithmNotNone()
确认令牌算法声明(alg
)未设置为无。
如果提供的令牌有任何问题,每个验证方法都会抛出 ReallySimpleJWT\Exception\ValidateException
。
自定义编码
默认情况下,该库使用 hash_hmac()
通过 sha256 算法哈希和编码 JWT 签名。如果开发者想使用自定义的编码形式,只需生成一个符合 ReallySimpleJWT\Interfaces\Encode
接口的自定义编码类。然后可以将它注入到 ReallySimpleJWT\Build
和 ReallySimpleJWT\Validate
类中。
interface EncodeInterface { public function getAlgorithm(): string; public function encode(string $toEncode): string; public function signature(string $header, string $payload): string; }
错误信息和代码
在创建、解析和验证 JWT 令牌的过程中,ReallySimpleJWT 库会在多种情况下抛出异常来突出显示问题。错误代码、消息及其说明如下表所示。
可能抛出六种异常类型
ReallySimpleJWT\Exception\BuildException
ReallySimpleJWT\Exception\EncodeException
ReallySimpleJWT\Exception\JwtException
ReallySimpleJWT\Exception\ParsedException
ReallySimpleJWT\Exception\TokensException
ReallySimpleJWT\Exception\ValidateException
令牌安全
JWT RFC 7519 允许创建没有签名和没有加密/哈希签名的令牌。然而,ReallySimpleJWT 库默认强制执行安全性,因为没有合理的理由不这样做。所有创建的令牌都必须有一个签名和一个强密钥,但库可以解析和验证没有密钥或强密钥的令牌。库不会验证没有签名的令牌。
默认情况下,ReallySimpleJWT 库提供了两种编码实现,ReallySimpleJWT\Encoders\EncodeHS256
和 ReallySimpleJWT\Encoders\EncodeHS256Strong
。后者强制执行严格的密钥安全性,并默认用于通过 Token
和 Tokens
类创建令牌。EncodeHS256
不强制执行严格的密钥安全性,可以在需要时与 Build
类一起使用来创建令牌。此外,还可以通过实现 ReallySimpleJWT\Interfaces\Encode
接口创建自定义编码类。参见自定义编码部分。
密钥强度
此JWT库通过EncodeHS256Strong
类强制执行严格的密钥安全性。提供的密钥长度必须至少为12个字符;包含数字;大小写字母;以及以下特殊字符之一:*&!@%^#$
。
// Bad Secret secret123 // Good Secret sec!ReT423*&
原因是存在大量的JWT破解工具,这意味着弱密钥很容易被破解,从而使JWT提供的签名安全性变得无用。
与PSR-JWT中间件的框架集成
您可以使用PSR-JWT
库轻松地将ReallySimpleJWT与符合PSR-7 / PSR-15
规范的框架(如Slim PHP和Laminas)集成。通过使用PSR-JWT库。
例如,与Slim PHP的集成只需几行代码
// Can be added to any routes file in Slim, often index.php. require '../../vendor/autoload.php'; $app->get('/jwt', function (Request $request, Response $response) { $response->getBody()->write("JSON Web Token is Valid!"); return $response; })->add(\PsrJwt\Factory\JwtAuth::middleware('Secret123!456$', 'jwt', 'Authentication Failed'));
请阅读PSR-JWT文档,了解关于ReallySimpleJWT的集成选项。
与RS-JWT的浏览器集成
当您创建JSON Web Tokens时,您可能希望阅读浏览器中包含在头和负载声明中的某些信息。
如果您这样做,我们有一个名为RS-JWT的NPM软件包。
安装
npm install --save rs-jwt
用法
import { parseJwt } from 'rs-jwt' const result = parseJwt('json.web.token') // Return the header claims as an object. const header = result.getHeader() // Access the type claim. console.log(header.typ) // Return the payload claims as an object. const payload = result.getPayload() // Access the expiry claim. console.log(payload.exp)
许可证
MIT
作者
Rob Waller
Twitter: @RobDWaller