Hướng dẫn decode rs256 jwt php

HS256 chỉ được sử dụng nếu bạn sử dụng mật khẩu để ký mã thông báo. Firebase sử dụng RS256 khi phát hành mã thông báo, do đó, bạn cần các khóa công khai từ URL đã cho và bạn cần đặt thuật toán thành RS256.

Cũng lưu ý rằng các dấu hiệu bạn nhận được trong ứng dụng của bạn không phải là một mảng mà là một chuỗi ký tự có 3 phần: header, body, và signature. Mỗi phần được phân tách bằng dấu a ., do đó nó cung cấp cho bạn một chuỗi đơn giản:header.body.signature

Những gì bạn cần làm để xác minh mã thông báo là tải xuống các khóa công khai thường xuyên từ URL đã cho (kiểm tra Cache-Controltiêu đề để biết thông tin đó) và lưu nó (JSON) trong một tệp, vì vậy bạn sẽ không phải truy xuất nó mỗi lần. thời gian bạn cần kiểm tra JWT. Sau đó, bạn có thể đọc trong tệp và giải mã JSON. Đối tượng được giải mã có thể được chuyển cho JWT::decode(...)hàm. Đây là một mẫu ngắn:

$pkeys_raw = file_get_contents("cached_public_keys.json");
$pkeys = json_decode($pkeys_raw, true);

$decoded = JWT::decode($token, $pkeys, ["RS256"]);

Bây giờ $decodedbiến chứa trọng tải của mã thông báo. Khi bạn có đối tượng được giải mã, bạn vẫn cần xác minh nó. Theo hướng dẫn về xác minh mã thông báo ID, bạn phải kiểm tra những điều sau:

  • exp là trong tương lai
  • iat là trong quá khứ
  • iss: https://securetoken.google.com/
  • aud:
  • sub không trống

Vì vậy, ví dụ: bạn có thể kiểm tra issnhư sau ( FIREBASE_APP_IDID ứng dụng từ bảng điều khiển firebase ở đâu):

$iss_is_valid = isset($decoded->iss) && $decoded->iss === "https://securetoken.google.com/" . FIREBASE_APP_ID;

Đây là một mẫu hoàn chỉnh để làm mới các phím và truy xuất chúng.

Tuyên bố từ chối trách nhiệm: Tôi chưa thử nghiệm nó và điều này về cơ bản chỉ dành cho mục đích thông tin.

$keys_file = "securetoken.json"; // the file for the downloaded public keys
$cache_file = "pkeys.cache"; // this file contains the next time the system has to revalidate the keys

/**
 * Checks whether new keys should be downloaded, and retrieves them, if needed.
 */
function checkKeys()
{
    if (file_exists($cache_file)) {
        $fp = fopen($cache_file, "r+");

        if (flock($fp, LOCK_SH)) {
            $contents = fread($fp, filesize($cache_file));
            if ($contents > time()) {
                flock($fp, LOCK_UN);
            } elseif (flock($fp, LOCK_EX)) { // upgrading the lock to exclusive (write)
                // here we need to revalidate since another process could've got to the LOCK_EX part before this
                if (fread($fp, filesize($this->cache_file)) <= time()) {
                    $this->refreshKeys($fp);
                }
                flock($fp, LOCK_UN);
            } else {
                throw new \RuntimeException('Cannot refresh keys: file lock upgrade error.');
            }
        } else {
            // you need to handle this by signaling error
            throw new \RuntimeException('Cannot refresh keys: file lock error.');
        }

        fclose($fp);
    } else {
        refreshKeys();
    }
}

/**
 * Downloads the public keys and writes them in a file. This also sets the new cache revalidation time.
 * @param null $fp the file pointer of the cache time file
 */
function refreshKeys($fp = null)
{
    $ch = curl_init();
    curl_setopt($ch, CURLOPT_URL, "https://www.googleapis.com/robot/v1/metadata/x509/");
    curl_setopt($ch, CURLOPT_RETURNTRANSFER, 1);
    curl_setopt($ch, CURLOPT_HEADER, 1);

    $data = curl_exec($ch);

    $header_size = curl_getinfo($ch, CURLINFO_HEADER_SIZE);
    $headers = trim(substr($data, 0, $header_size));
    $raw_keys = trim(substr($data, $header_size));

    if (preg_match('/age:[ ]+?(\d+)/i', $headers, $age_matches) === 1) {
        $age = $age_matches[1];

        if (preg_match('/cache-control:.+?max-age=(\d+)/i', $headers, $max_age_matches) === 1) {
            $valid_for = $max_age_matches[1] - $age;
            ftruncate($fp, 0);
            fwrite($fp, "" . (time() + $valid_for));
            fflush($fp);
            // $fp will be closed outside, we don't have to

            $fp_keys = fopen($keys_file, "w");
            if (flock($fp_keys, LOCK_EX)) {
                fwrite($fp_keys, $raw_keys);
                fflush($fp_keys);
                flock($fp_keys, LOCK_UN);
            }
            fclose($fp_keys);
        }
    }
}

/**
 * Retrieves the downloaded keys.
 * This should be called anytime you need the keys (i.e. for decoding / verification).
 * @return null|string
 */
function getKeys()
{
    $fp = fopen($keys_file, "r");
    $keys = null;

    if (flock($fp, LOCK_SH)) {
        $keys = fread($fp, filesize($keys_file));
        flock($fp, LOCK_UN);
    }

    fclose($fp);

    return $keys;
}

Điều tốt nhất là lên lịch cho một cronjob để gọi checkKeys()bất cứ khi nào cần, nhưng tôi không biết liệu nhà cung cấp của bạn có cho phép điều đó hay không. Thay vì điều đó, bạn có thể thực hiện việc này cho mọi yêu cầu:

checkKeys();
$pkeys_raw = getKeys(); // check if $raw_keys is not null before using it!

27 hữu ích 5 bình luận chia sẻ