placetopay / reallysimplejwt
一个用于生成用户认证JSON Web Tokens的简单库。
Requires
- php: >=7.1.0
Requires (Dev)
- phpmd/phpmd: 2.6.*
- phpstan/phpstan: ^0.10
- phpunit/phpunit: ^7.0
- squizlabs/php_codesniffer: ^3.0
This package is not auto-updated.
Last update: 2024-09-21 00:03:34 UTC
README
这是一个简单的PHP库,用于创建使用HMAC SHA256签名签名的JSON Web Tokens。对于基本使用,该库公开了一个静态接口,允许开发者创建存储用户标识和过期时间的令牌。
该库也支持扩展,开发者可以定义自己的编码标准,设置所有RFC标准 JWT声明,并设置自己的私有声明。
内容
什么是JSON Web Token?
JSON Web Tokens是一种创建对用户或系统声明的URL友好访问令牌的标准。
令牌分为三个部分;头部、有效负载和签名;每个部分由点分隔。每个部分都使用base64url标准进行编码,请参阅RFC。
一个示例JWT
eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiaWF0IjoxNTE2MjM5MDIyfQ.SflKxwRJSMeKKF2QT4fwpMeJf36POk6yJV_adQssw5c
头部和有效负载都是包含多个声明的编码JSON字符串
// Header { "alg": "HS256", "typ": "JWT" } // Payload { "sub": "1234567890", "name": "John Doe", "iat": 1516239022 }
声明是一个键值对,例如"typ": "JWT",请阅读RFC 7519以了解更多关于JSON Web Token声明的信息。
通过签名实现令牌安全性,签名由头部、有效负载和只有令牌作者知道的密钥组成。这些信息被散列然后使用base64url编码。
如果恶意用户试图编辑头部或有效负载声明,只要您使用强大的密钥,他们将无法复制签名。有关更多信息,请参阅令牌安全性。
设置
通过命令行Composer
composer require placetopay/reallysimplejwt
通过composer.json
"require": { "placetopay/reallysimplejwt": "^2.1" }
基本用法
对于基本用法,该库通过ReallySimpleJWT\Token类公开了一系列静态方法,允许开发者创建和验证基本的JSON Web Tokens。
创建令牌
调用create()静态方法,传入用户标识、密钥、过期日期时间数字和令牌发行者。
在成功的情况下,这将返回一个令牌字符串,在失败的情况下将抛出ReallySimpleJWT\Exception\ValidateException异常。
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);
获取头部和有效负载声明数据
要从头部或载荷中检索令牌声明数据,请调用 getHeader() 和或 getPayload() 静态方法。
这两个方法在成功时将返回一个关联数组,在失败时抛出异常。
use ReallySimpleJWT\Token; $token = 'aaa.bbb.ccc'; $secret = 'sec!ReT423*&' // Return the header claims Token::getHeader($token, $secret); // Return the payload claims Token::getPayload($token, $secret);
工厂方法
ReallySimpleJWT\Token 类还提供了两个工厂方法,用于访问核心的 ReallySimpleJWT\Build 和 ReallySimpleJWT\Parse 类。
Token::builder(); // Returns an instance of ReallySimpleJWT\Build Token::parser($token, $secret); // Returns an instance of ReallySimpleJWT\Parse
高级用法
为了创建自定义的 JSON Web Tokens,开发人员需要直接访问 ReallySimpleJWT\Build 和 ReallySimpleJWT\Parse 类。
创建自定义令牌
ReallySimpleJWT\Build 类允许您创建一个完全独特的 JSON Web Token。它为所有由 RFC 定义的头和载荷声明提供了辅助方法。例如,setIssuer() 方法将添加 iss 声明到令牌载荷。
该类还允许开发人员通过 setHeaderClaim() 和 setPayloadClaim() 方法设置自定义的头和载荷声明。
可以将这些方法链接在一起,当调用 build() 方法时,令牌将在 ReallySimpleJWT\Jwt 对象内生成并返回。
use ReallySimpleJWT\Build; use ReallySimpleJWT\Validate; use ReallySimpleJWT\Encode; $build = new Build('JWT', new Validate(), new Encode()); $token = $build->setContentType('JWT') ->setHeaderClaim('info', 'foo') ->setSecret('!secReT$123*') ->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() 和 getSecret()。前者返回生成的 JSON Web Token,后者返回用于令牌签名的密钥。
要使用 ReallySimpleJWT\Parse 类解析 JSON Web Token,开发人员必须首先通过注入令牌和密钥创建一个新的 ReallySimpleJWT\Jwt 对象。
use ReallySimpleJWT\Jwt; $token = 'aaa.bbb.ccc'; $secret = '!secReT$123*'; $jwt = new Jwt($token, $secret); // Return the token $jwt->getToken(); // Return the secret $jwt->getSecret();
解析和验证令牌
ReallySimpleJWT\Parse 类允许开发人员解析和验证 JSON Web Token。有三个验证方法可用,都可以链接使用。
validate()确认令牌的结构和签名的有效性。validateExpiration()确认令牌过期声明 (exp) 没有过期。validateNotBefore()确认令牌不早于声明 (nbf) 已经过期。
如果提供的令牌有任何问题,每个验证方法都将抛出 ReallySimpleJWT\Exception\ValidateException。
在验证完成后应调用 parse() 方法,该方法将解码 JSON Web Token。然后,它将结果作为 ReallySimpleJWT\Parsed 对象返回。这将提供对令牌在头部和载荷中持有的声明数据的访问。
use ReallySimpleJWT\Parse; use ReallySimpleJWT\Jwt; use ReallySimpleJWT\Validate; use ReallySimpleJWT\Encode; $token = 'aaa.bbb.ccc'; $secret = '!secReT$123*'; $jwt = new Jwt($token, $secret); $parse = new Parse($jwt, new Validate(), new Encode()); $parsed = $parse->validate() ->validateExpiration() ->validateNotBefore() ->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()
自定义编码
默认情况下,此库通过 sha256 算法使用 hash_hmac() 对 JWT 签名进行哈希和编码。如果开发人员想使用自定义的编码形式,只需生成一个符合 ReallySimpleJWT\Interfaces\EncodeInterface 的自定义编码类即可。
interface EncodeInterface { public function getAlgorithm(): string; public function encode(string $toEncode): string; public function decode(string $toDecode): string; public function signature(string $header, string $payload, string $secret): string; }
错误信息和代码
在创建和解析 JWT 令牌的许多情况下,ReallySimpleJWT 库将抛出异常以突出显示问题。以下列出了错误代码、消息及其说明。
令牌安全性
JWT (JSON Web Token) 标准RFC 7519允许创建不带签名和不带安全/加密签名的令牌。然而,ReallySimpleJWT库默认强制执行安全性,因为没有合理的理由不这样做。所有创建的令牌都必须有一个签名和一个强大的密钥,但该库将验证不带密钥或强密钥的令牌。该库不会验证不带签名的令牌。
可以通过创建一个实现ReallySimpleJWT\Interfaces\EncodeInterface的自定义编码类来编辑和增强签名的实现及其安全级别。请参阅自定义编码部分。
签名密钥
这个JWT库不强制实施严格的密钥字符串安全性。然而,设置一个严格的模式来验证密钥是一个好的实践。
# setting a secret string pattern for validation \ReallySimpleJWT\Validate::$secretPattern = '/^.*$/'; // Same validation without special characters \ReallySimpleJWT\Validate::$secretPattern = /^.*(?=.{12,}+)(?=.*[0-9]+)(?=.*[A-Z]+)(?=.*[a-z]+).*$/; // Bad Secret secret123 // Good Secret sec!ReT423*&
原因是存在许多JWT破解工具,这意味着弱密钥很容易被破解,从而使JWT提供的安全性变得无用。
许可证
MIT
作者
Rob Waller
Twitter: @robdwaller