【问题标题】:PHP JWT (JSON Web Token) with RSA signature without library带有 RSA 签名的 PHP JWT(JSON Web 令牌),没有库
【发布时间】:2021-07-03 07:10:26
【问题描述】:

有人知道在 PHP 中使用 JWT(JSON Web 令牌)和 RSA 签名而没有库的一些解决方案吗?我非常努力地寻找没有库或不使用作曲家的解决方案。我发现的所有选项都使用某种库。

【问题讨论】:

    标签: php openssl jwt rsa


    【解决方案1】:

    我在途中使用其他示例制作了自己的解决方案。下面我们有 3 个用例和特定的 PHP 代码供任何想要使用的人使用:

    1. 使用 openssl 库创建用于签署 JWT 的 RSA 私钥和公钥。
    2. 创建 JWT 令牌并使用 RSA 私钥进行签名。
    3. 使用 RSA 公钥验证 JWT 的签名令牌。
    4. 反向加密示例。使用公钥加密 => 私钥解密。

    1 - 使用 openssl 库创建用于签署 JWT 的 RSA 私钥和公钥:

    // ====================== OPENSSL KEY CREATE METHOD ==================
    
    // URL of the source: https://8gwifi.org/docs/php-asym.jsp
    // I tried all 3 types of keys, but only RSA type works.
    
    $password = "password"; // Change it for what value you want
    
    $config = array(  
        "digest_alg" => "sha512",  
        "private_key_bits" => 2048,  
        "private_key_type" => OPENSSL_KEYTYPE_RSA,
    );  
     
    // Create the keypair  
    $res = openssl_pkey_new($config);  
    // Get private key  
    openssl_pkey_export($res, $privkey);  
    // Get public key  
    $pubkey = openssl_pkey_get_details($res);  
    $pubkey = $pubkey["key"];  
      
    echo "====PKCS1 RSA Key in Non Encrypted Format ====\n";  
    var_dump($privkey);  
    echo "====PKCS1 RSA Key in Encrypted Format====\n ";  
      
    // Get private key in Encrypted Format  
    openssl_pkey_export($res, $privkey,$password);  
    // Get public key  
    $pubkey = openssl_pkey_get_details($res);  
    $pubkey = $pubkey["key"];  
    var_dump($privkey);  
    echo "RSA Public Key \n ";  
    var_dump($pubkey); 
    

    2 - 创建 JWT 令牌并使用 RSA 私钥签名和 3 - 使用 RSA 公钥验证 JWT 的签名令牌:

    
    // ====================== JWT WITH ENCRYPT AND DECRYPT ==================
    
    // ===== Variables definition
    
    $keyPrivatePassword = 'password';
    $keyPrivatePath = "private.key";
    $keyPublicPath = "public.key";
    $cryptMaxCharsValue = 245; // There are char limitations on openssl_private_encrypt() and in the url below are explained how define this value based on openssl key format: https://www.php.net/manual/en/function.openssl-private-encrypt.php#119810
    
    $debug = Array(
        'print-msgs' => true,
        'print-openssl-errors' => false,
        'print-openssl-crypt' => false,
        'print-key-details' => false,
    );
    
    // ##################### START DEFINITION OF JWT
    
    // ===== Definition of header
    
    $header = [
       'alg' => 'RSA',
       'typ' => 'JWT'
    ];
    
    $header = json_encode($header);
    $header = base64_encode($header);
    
    // ===== Definition of payload
    
    $payload = [
        'iss' => 'localhost', // The issuer of the token
        'sub' => 'test', // The subject of the token
        'aud' => 'private', // The audience of the token
        'exp' => '1300819380', // This will define the expiration in NumericDate value. The expiration MUST be after the current date/time.
        'data' => [ // Change it with use case data
            'name' => 'User',
            'email' => 'user@mail'
        ]
    ];
    
    $payload = json_encode($payload);
    $payload = base64_encode($payload);
    
    // ===== START ENCRYPT SIGN JWT
    
    $data = $header.".".$payload;
    
    // ===== Print example header
    
    if($debug['print-msgs']){
        echo "JWT CRYPT / DECRYPT EXAMPLE\n\n";
        echo "Value of header . payload: ".$data."\n";
    }
    
    // ===== Open private path and return this in string format
    
    $fp = fopen($keyPrivatePath,"r");
    $keyPrivateString = fread($fp,8192);
    fclose($fp);
    
    // ===== Open private key string and return 'resourse'
    
    if(isset($keyPrivatePassword)){
        $resPrivateKey = openssl_get_privatekey($keyPrivateString,$keyPrivatePassword);
    } else {
        $resPrivateKey = openssl_get_privatekey($keyPrivateString);
    }
    
    // ===== If any openssl error occurs, print it
    
    $openSSLError = false;
    if($debug['print-openssl-errors']){
        while($msg = openssl_error_string()){
            echo $msg . "\n";
            $openSSLError = true;
        }
    }
    
    // ===== See details of a private key
    
    if($debug['print-key-details']){
        $keyPrivateDetails = openssl_pkey_get_details($resPrivateKey);
    
        echo "Private Key Details:\n";
        echo print_r($keyPrivateDetails,true)."\n";
    }
    
    // ===== Crypt data in parts if necessary. When char limit of data is upper than 'cryptMaxCharsValue'.
    
    $rawDataSource = $data;
    
    $countCrypt = 0;
    $partialData = '';
    $encodedData = '';
    $split = str_split($rawDataSource , $cryptMaxCharsValue);
    foreach($split as $part){
        openssl_private_encrypt($part, $partialData, $resPrivateKey);
        
        if($debug['print-openssl-crypt']){
            $countCrypt++;
            echo "CRYPT PART ".$countCrypt.": ".$partialData."\n";
        }
        
        $encodedData .= (strlen($encodedData) > 0 ? '.':'') . base64_encode($partialData);
    }
    
    // ===== If any openssl error occurs, print it
    
    $openSSLError = false;
    if($debug['print-openssl-errors']){
        while($msg = openssl_error_string()){
            echo $msg . "\n";
            $openSSLError = true;
        }
    }
    
    // ===== Print data encrypted
    
    if($debug['print-msgs']){
        if($openSSLError) echo "\n";
    
        echo "Encrypted signature: ".$encodedData."\n";
    }
    
    // ===== Encode base64 again to remove dots (Dots are used in JWT syntaxe)
    
    $encodedData = base64_encode($encodedData);
    
    if($debug['print-msgs']){
        echo "Encrypted signature Base64: ".$encodedData."\n";
    }
    
    $signature = $encodedData;
    
    // ===== FINISH JWT
    
    $JWTToken = $header.".".$payload.".".$signature;
    
    if($debug['print-msgs']){
        echo "\nJWT Token: ".$JWTToken."\n\n";
        echo "FINISH CREATE JWT!\n\n";
    }
    
    // ##################### START VALIDATE JWT
    
    $token = $JWTToken;
    
    $part = explode(".",$token);
    
    $header = $part[0];
    $payload = $part[1];
    $signature = $part[2];
    
    $encodedData = $signature;
    
    // ===== Open public path and return this in string format
    
    $fp = fopen($keyPublicPath,"r");
    $chavePublicaString = fread($fp,8192);
    fclose($fp);
    
    // ===== Open public key string and return 'resourse'
    
    $resPublicKey = openssl_get_publickey($chavePublicaString);
    
    // ===== If any openssl error occurs, print it
    
    $openSSLError = false;
    if($debug['print-openssl-errors']){
        while($msg = openssl_error_string()){
            echo $msg . "\n";
            $openSSLError = true;
        }
    }
    
    // ===== See details of a public key
    
    if($debug['print-key-details']){
        $keyPublicDetails = openssl_pkey_get_details($resPublicKey);
    
        echo "Public Key Details:\n";
        echo print_r($keyPublicDetails,true)."\n";
    }
    
    // ===== Decode base64 to reaveal dots (Dots are used in JWT syntaxe)
    
    $encodedData = base64_decode($encodedData);
    
    if($debug['print-msgs']){
        echo "Encrypted signature: ".$encodedData."\n";
    }
    
    // ===== Decrypt data in parts if necessary. Using dots as split separator.
    
    $rawEncodedData = $encodedData;
    
    $countCrypt = 0;
    $partialDecodedData = '';
    $decodedData = '';
    $split2 = explode('.',$rawEncodedData);
    foreach($split2 as $part2){
        $part2 = base64_decode($part2);
        
        if($debug['print-openssl-crypt']){
            $countCrypt++;
            echo "CRYPT PART ".$countCrypt.": ".$part2."\n";
        }
        
        openssl_public_decrypt($part2, $partialDecodedData, $resPublicKey);
        $decodedData .= $partialDecodedData;
    }
    
    // ===== Print data decrypted
    
    if($debug['print-msgs']){
        echo "Decrypted signature: ".$decodedData."\n";
    }
    
    // ===== If any openssl error occurs, print it
    
    $openSSLError = false;
    if($debug['print-openssl-errors']){
        while($msg = openssl_error_string()){
            echo $msg . "\n";
            $openSSLError = true;
        }
    }
    
    // ===== Validate JWT
    
    if($debug['print-msgs']){
        echo "\nFINISH VALIDATE JWT!\n\n";
    }
    
    if($header.".".$payload === $decodedData){
        echo "VALID JWT!\n\n";
        
        $payload = base64_decode($payload);
        $payload = json_decode($payload,true);
        
        echo "Payload:\n";
        echo print_r($payload,true);
    } else {
        echo "INVALID JWT!";
    }
    

    4 - 反向加密的示例。使用公钥加密 => 私钥解密:

    // ====================== ENCRYPTATION INVERSE ==================
    // If want to change Private Key Encryptation -> Public Key Decryptation to Public Key Encryptation -> Private Key Decryptation this example can help.
    
    $keyPrivatePassword = 'password';
    $keyPrivatePath = "private.key";
    $keyPublicPath = "public.key";
    
    // ===== Open private path and return this in string format
    
    $fp = fopen($keyPrivatePath,"r");
    $keyPrivateString = fread($fp,8192);
    fclose($fp);
    
    // ===== Open public path and return this in string format
    
    $fp = fopen($keyPublicPath,"r");
    $keyPublicString = fread($fp,8192);
    fclose($fp);
    
    // ===== Test of encryptation
    
    $data = 'Data to encrypt';
    
    $resPrivateKey = openssl_get_privatekey($keyPrivateString,$keyPrivatePassword);
    $resPublicKey = openssl_get_publickey($keyPublicString);
    
    echo 'Data: '.$data."\n";
    
    openssl_public_encrypt($data, $encData, $resPublicKey);
    
    echo 'encData: '.$encData."\n";
    
    openssl_private_decrypt($encData, $decData, $resPrivateKey);
    
    echo 'decData: '.$decData."\n";
    

    【讨论】:

      猜你喜欢
      • 2014-11-27
      • 2023-04-08
      • 2016-12-25
      • 2018-07-26
      • 2016-02-19
      • 2017-05-30
      • 2018-10-20
      • 2016-08-01
      • 2013-06-02
      相关资源
      最近更新 更多