JWT、JWS、JWE 库

1.0-beta 2020-08-22 18:05 UTC

This package is not auto-updated.

Last update: 2024-09-30 10:48:27 UTC


README

易于使用、轻量级、用户友好的 JWT 库 ** 无依赖 ** - 所有算法仅使用 PHP OpenSSL 实现。

免责声明

2020年8月22日 - BETA - 所有功能似乎都正常工作,

未完全测试安全性 / 未完全符合 RFC 标准。自行承担风险!

欢迎使用此库,并通过发现错误和实现缺失算法来帮助我改进它。

它能做什么?

  • JWS - HS256 - 签名/验证 - 使用共享密钥
  • JWS - HS384 - 签名/验证 - 使用共享密钥
  • JWS - HS512 - 签名/验证 - 使用共享密钥
  • JWS - RS256 - 签名/验证 - 使用私钥和公钥
  • JWS - RS384 - 签名/验证 - 使用私钥和公钥
  • JWS - RS512 - 签名/验证 - 使用私钥和公钥
  • JWE - RSA1_5 + A128CBC-HS256 - 加密/解密 - 使用私钥和公钥
  • JWE - RSA1_5 + A192CBC-HS384 - 加密/解密 - 使用私钥和公钥
  • JWE - RSA1_5 + A256CBC-HS512 - 加密/解密 - 使用私钥和公钥
  • JWE - RSA1_5 + A128GCM - 加密/解密 - 使用私钥和公钥
  • JWE - RSA1_5 + A192GCM - 加密/解密 - 使用私钥和公钥
  • JWE - RSA1_5 + A256GCM - 加密/解密 - 使用私钥和公钥

目录

  1. 安装

  2. 构建器

  3. 构建器方法

  4. 检查器

  5. 检查器方法

  6. 算法

  7. 贡献

  8. 联系

安装

运行以下 composer 命令

composer require itaiarbel/jwt

然后在您的项目中使用它

use Itaiarbel\Jwt\Jwt; 

构建器

允许您构建 JWT,然后对其进行签名/加密。

使用示例

 $jws= Jwt::Builder()            
            ->jti() 
            ->claim('iss','me')
            ->claim('aud','you')
            ->exp(3600)  
            ->claim('sub','123123')                                                
            ->sign('SuPerSeCrEtKeY','HS256');

echo $jws->jwt; //your jws string

$private_rsa_key='
-----BEGIN PRIVATE KEY-----
...  generate your own 2048bit/4096bit RSA keys ...
-----END PRIVATE KEY-----';

$public_rsa_key='
-----BEGIN PUBLIC KEY-----
...  generate your own 2048bit/4096bit RSA keys ...
-----END PUBLIC KEY-----';


 $jws2= Jwt::Builder()
            ->header('kid','38890') //optional key id - for key menegment
			  ->jti()
            ->claim('iss','me')
            ->claim('aud','you')
            ->exp(3600)  
            ->nbf(600)         
            ->claim('sub','123123')                                    
            ->claim('user_verified','1')
            ->sign($private_rsa_key,'RS256'); 

echo $jws2->jwt; //your jws signed string using the private key


$private_rsa_key='
-----BEGIN PRIVATE KEY-----
...  generate your own 2048bit/4096bit RSA keys ...
-----END PRIVATE KEY-----';

$jwe= Jwt::Builder()
            ->header('kid','1') 
            ->jti() 
            ->claim('iss','me') 
            ->claim('aud','you')
            ->exp(3600)
            ->nbf(600)         
            ->claim('sub','123123')                                    
            ->claim('user_verified','1')
            ->encrypt($private_rsa_key,'RSA1_5','A128CBC-HS256');
                        
 echo $jwe->jwt; //your jwe string encrypted using the private key
 

##构建器方法

claim(key, val) / claims([key=>val,key=>val...]) : 向令牌的有效负载部分添加声明/声明

->claim('first_name','john') //add claim
->claim('last_name','doe') // one by one
->claims([  				    //or add multiple claims as array
		   'first_name'=>'john',
		   'last_name'=>'doe'
		  ])

->claim('user',[  //adds json object claim under 'user'
			'user_id' => '123',
		   'first_name'=>'john',
		   'last_name'=>'doe'
		  ]);		  

header(key, val) : 向令牌的标头部分添加声明(注意:JWE 中的标头声明不被加密)

->header('kid','123') //set key id

exp(secs,server_ts[opt]) : 添加 'exp' 令牌过期时间声明为 time()+secs,您可以为不同的时区设置服务器时间戳。

->exp(3600) //time()+3600
->exp(3600,$ts) // $ts + 3600

nfb(secs) : 添加 'nbf' 令牌未生效之前声明为 time()+secs

->nbf(600) //time()+600
->nbf(600,$ts) //$ts+600

jti(val[opt]) : 添加 'jti' 令牌 ID 声明,如果没有提供参数,则为自动生成的随机 GUID

->jti() //e.g b1e029d4-c452-4ab4-9c0a-39db17896224
->jti('random-id-123-123') //or use your own id
->claim('jti','random-id-123-123') //you can use claim function instead

iss(val)/issuer(val) : 添加 'iss' 令牌发行者声明

 ->iss('me') 
 ->issuer('me') //or
 ->claim('iss','me') //or 

sign(key, alg) : 完成构建器并签名 JWT。 - > JWS

->sign('SuPerSeCrEtKeY','HS512'); //sign with HMAC-SHA512 using a secret key
->sign($private_key_pem,'RS512'); //sign with RSA-SHA512 using a private key

encrypt(key, alg, enc) : 完成构建器并加密 JWT。 -> JWE

->encrypt($private_key_pem,'RSA1_5','A256CBC-HS512'); //encrypt using RSA & AES256CBC-HS512
->encrypt($private_key_pem,'RSA1_5','A256GCM'); //encrypt using RSA & AES128GCM

检查器

使用示例

JWS 验证

    //this is a 5y valid token signed with HS256 with  key 'SuPerSeCrEtKeY'
    $jws_string="eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJqdGkiOiIyM2YxYmY5Ny02NTlkLTQ2MjAtOWY1Ni0yOGVjMWUxN2MyYmQiLCJpc3MiOiJtZSIsImF1ZCI6InlvdSIsImlhdCI6MTU5ODExMjQ3NSwiZXhwIjoxNzU1NzkyNDc1LCJzdWIiOiIxMjMxMjMifQ.JSIWCGxG8ay-h3LKoZ9pCd5sx4cqK-Wqn2pKtJoBAn4";
    
    try{
        $jws= Jwt::Checker($jws_string)->verify('SuPerSeCrEtKeY','HS256');
    }catch(Exception $e){
        //exception will happen if the input is not valid jwt
        $jws=false;
        echo "INVALID TOKEN INPUT!<br>";         
    }
            
        if ($jws && $jws->validate()){  //validates exp & nbf & signiture here            
            echo "VALID TOKEN!!<br>";                       
            print_r($jws->getClaims()); //print all claims
            echo '<br><br>';
        }else{
            echo "TOKEN NOT VALID!!<br>";           
        }
        
        
        //same as above + checking extra fields like issuer        
        if ( 
            $jws &&                          //ckeck input of token
            $jws->verified && 			     // Signature verification
            $jws->checkExp() && 			  //If exp timstamp passed                       
            $jws->checkNbf() &&                 //checkNbf
            //up to here - same as calling:  $jws->validate()
            $jws->iss('me') && 			  //If issuer is"me"
            $jws->aud('you') 			  //If audience is "you"            
            ){
               echo "VALID TOKEN FROM ME TO YOU!!<br>";     
               print_r($jws->getClaims()); //print all claims
               echo '<br><br>';
           }else{
               echo "TOKEN NOT VALID!!<br>";
        }        

JWE 解密


$public_rsa_key='
-----BEGIN PUBLIC KEY-----
...  generate your own 2048bit/4096bit RSA keys ...
-----END PUBLIC KEY-----';


     try{                   
            //start checker with jwt string input
            $jwe= Jwt::Checker($user_input_jwe);
 
            //you can get header claims before decrypting like: alg,enc,kid ect...
			  $header= $jwe->getHeaderClaims();
			  
		
            //$jwe->decrypt($public_key,$header['alg'],$header['enc']); //extract alg &enc from header           
            $jwe->decrypt($public_rsa_key,'RSA1_5','A128CBC-HS256');// or you can decrypt using known preset alg & enc
        
        }catch(Exception $e){ //error decrypting/parsing
            $jwe=false;            
        }
             
             
                         
        if ($jwe && $jwe->validate()){  //validates exp & nbf & decryption here            
            echo "VALID TOKEN!!<br>";                       
            print_r($jwe->getClaims()); //print all claims
            echo '<br><br>';
        }else{
            echo "TOKEN NOT VALID!!<br>";           
        }
        
        
        //same as above + checking extra fields like issuer        
        if ( 
            $jwe &&                          //ckeck input of token
            $jwe->decrypted && 			     // Signature verification
            $jwe->checkExp() && 			  //If exp timstamp passed                       
            $jwe->checkNbf() &&                 //checkNbf
            //up to here - same as calling:  $jws->validate()
            $jwe->iss('me') && 			  //If issuer is"me"
            $jwe->aud('you') 			  //If audience is "you"            
            ){
               echo "VALID TOKEN FROM ME TO YOU!!<br>";     
               print_r($jwe->getClaims()); //print all claims
               echo '<br><br>';
           }else{
               echo "TOKEN NOT VALID!!<br>";
        }   
            

注意:已验证并不表示有效令牌,它仅检查签名,不检查令牌时间的有效性,您必须自行检查过期时间戳/nbf/iss 黑名单/捕获/数据库等...

##检查器方法

verify(key/secret,alg) - 使用公钥/密钥验证 JWS

$jws->verify($public_key_pem,'RS512');
$jws->verify('secretkey','HS512');

decrypt(key/secret,alg,enc) - 使用公钥解密 JWE

$jwe->decrypt($public_key_pem,'RSA1_5','A256CBC-HS512');

getHeaderClaims():array - 获取 JWE/JWS 中所有标头声明的数组

$jws->getHeaderClaims();

getHeaderClaim(name):string - 从标头获取特定声明

$jws->getHeaderClaim('kid');

hasHeaderClaim(name):bool - 如果标头声明存在,则返回 true/false

if($jws->hasHeaderClaim('kid')){
	$key= your_own_get_key_by_id(
		$jws->kid()
		);
	}

kid()/keyId():string - 从标头获取 'kid' 声明

$kid= $jwe->kid();
$kid= $jwe->keyId();

alg()/algorithm():string - 从标头获取 'alg' 声明

$alg = $jws->alg();
$alg = $jws->algorithm();

enc()/encryption():string - 从标头获取 'enc' 声明

$enc = $jwe->enc();
$enc = $jwe->encryption();

validate(server_ts[opt]):bool - 验证签名/解密 + exp + nbf

 if ($jwe && $jwe->validate()){
 	echo 'Token is valid and not expiered';
 }

checkExp(ts[opt]):bool - 如果 exp 声明时间已过,则返回 true/false

 if (!$jwe->checkExp()){
 	echo 'Token is expiered';
 }

checkNbf(ts[opt]):bool - 如果 nbf 时间不是在现在之前,则返回 true/false。注意:如果 nbf 声明不存在 - 返回 true,因为此声明是可选的

 if (!$jwe->checkNbf()){
 	echo 'Used Token too soon';
 }

checkClaim(name,expected_val):bool - 返回 true/false - 检查声明与预期值是否匹配

 if ($jwe->checkClaim('user_verified','1')){
 	echo 'User is Verified!';
 }

checkHeaderClaim(name,expected_val):bool - 返回 true/false - 检查头部声明与预期值是否匹配

 if ($jwe->checkHeaderClaim('kid','12')){
 	echo 'token is using key #12';
 }

getClaims():array - 获取所有声明的数组(如果令牌尚未解密,将返回空数组)

print_r($jws->getClaims());

getClaim(name):string - 通过名称获取特定声明(如果令牌尚未解密,将返回空字符串)

$username = $jws->getClaim('username');

hasClaim(name):bool - 如果声明存在则返回 true/false(如果令牌尚未解密,则返回 false)

if($jws->hasClaim('username')){
{ 
	echo 'hello '.$jws->getClaim('username');
}

iss()/issuer():string - 获取发行者 'iss' 声明

$jws->iss();
$jws->issuer();

sub()/subject():string - 获取主题 'sub' 声明

$user_id = $jws->sub();
$user_id = $jws->subject();

aud()/audience():string - 获取受众 'aud' 声明

$jws->aud();
$jws->audience();

exp()/expires():string - 获取过期时间 'exp' 声明

$jws->exp();
$jws->expires();

nbf()/notBefore():string - 获取不早于时间 'nbf' 声明

$jws->nbf();
$jws->notBefore();

iat()/issuedAt():string - 获取发行时间 'iat' 声明

$jws->iat();
$jws->issuedAt();

jti()/id():string - 获取令牌 ID 'jti' 声明

$jws->jti();
$jws->id();

算法

实现的算法

  • HS256 - HMAC-SHA256 - 签名/验证
  • HS384 - HMAC-SHA384 - 签名/验证
  • HS512 - HMAC-SHA512 - 签名/验证
  • RS256 - RSA-PKCS1-SHA256 - 签名/验证
  • RS384 - RSA-PKCS1-SHA384 - 签名/验证
  • RS512 - RSA-PKCS1-SHA512 - 签名/验证
  • RSA1_5 - 加密密钥/解密密钥
  • A128CBC_HS256 - AES-128-CBC SHA256 - 加密/解密
  • A192CBC_HS384 - AES-192-CBC SHA384 - 加密/解密
  • A256CBC_HS512 - AES-256-CBC SHA512 - 加密/解密
  • A128GCM - AES-128-GCM - 加密/解密
  • A192GCM - AES-192-GCM - 加密/解密
  • A256GCM - AES-256-GCM - 加密/解密

待办事项:算法 TODO:(也许你可以帮忙?)

  • dir
  • PS256
  • PS384
  • PS512
  • ES256
  • ES384
  • ES512
  • RSA-OAEP
  • RSA-OAEP-256
  • A128KW
  • A192KW
  • A256KW
  • ECDH-ES
  • ECDH-ES+A128KW
  • ECDH-ES+A192KW
  • ECDH-ES+A256KW
  • A128GCMKW
  • A192GCMKW
  • A256GCMKW
  • PBES2-HS256+A128KW
  • PBES2-HS384+A192KW
  • PBES2-HS512+A256KW

贡献

贡献方式

  • 添加算法
  • 查找错误
  • 修复错误
  • 改进现有代码

支持

  • 给我买一杯咖啡

联系

您可以通过itai@arbelis.com联系我