+
95
-

回答

gcloud access-token这个值谷歌cloud官方是通过gcloud 的客户端命令行获取的,需要下载到本地运行后获取

当然也有人根据这套协议写出了不需要命令行的代码,模拟了命令行的执行:

我们以cloudflare的worker为例,其他的编程语言可以通过ai更换:

// 配置变量

const PROJECT_ID = '';
const CLIENT_EMAIL = '';
const PRIVATE_KEY ="";

addEventListener("fetch", (event) => {
  event.respondWith(handleRequest(event.request));
});
async function handleRequest(request) {
const [token, err] = await exchangeJwtForAccessToken(signedJWT)
if (token === null) {
      console.log(`Invalid jwt token: ${err}`)
      return createErrorResponse(500, "api_error", "invalid authentication credentials");
}
}

function createErrorResponse(status, errorType, message) {
  const errorObject = { type: "error", error: { type: errorType, message: message } };
  return new Response(JSON.stringify(errorObject), {
      status: status,
      headers: {
          "Content-Type": "application/json",
          "Access-Control-Allow-Origin": "*",
      },
  });
}

async function createSignedJWT(email, pkey) {
  pkey = pkey.replace(/-----BEGIN PRIVATE KEY-----|-----END PRIVATE KEY-----|\r|\n|\\n/g, "");
  let cryptoKey = await crypto.subtle.importKey(
      "pkcs8",
      str2ab(atob(pkey)),
      {
          name: "RSASSA-PKCS1-v1_5",
          hash: { name: "SHA-256" },
      },
      false,
      ["sign"]
  );

  const authUrl = "https://www.googleapis.com/oauth2/v4/token";
  const issued = Math.floor(Date.now() / 1000);
  const expires = issued + 600;

  const header = {
      alg: "RS256",
      typ: "JWT",
  };

  const payload = {
      iss: email,
      aud: authUrl,
      iat: issued,
      exp: expires,
      scope: "https://www.googleapis.com/auth/cloud-platform",
  };

  const encodedHeader = urlSafeBase64Encode(JSON.stringify(header));
  const encodedPayload = urlSafeBase64Encode(JSON.stringify(payload));

  const unsignedToken = `${encodedHeader}.${encodedPayload}`;

  const signature = await crypto.subtle.sign(
      "RSASSA-PKCS1-v1_5",
      cryptoKey,
      str2ab(unsignedToken)
  );

  const encodedSignature = urlSafeBase64Encode(signature);
  return `${unsignedToken}.${encodedSignature}`;
}

async function exchangeJwtForAccessToken(signed_jwt) {
  const auth_url = "https://www.googleapis.com/oauth2/v4/token";
  const params = {
      grant_type: "urn:ietf:params:oauth:grant-type:jwt-bearer",
      assertion: signed_jwt,
  };

  const r = await fetch(auth_url, {
      method: "POST",
      headers: { "Content-Type": "application/x-www-form-urlencoded" },
      body: Object.entries(params)
          .map(([k, v]) => k + "=" + v)
          .join("&"),
  }).then((res) => res.json());

  if (r.access_token) {
      return [r.access_token, ""];
  }

  return [null, JSON.stringify(r)];
}

function str2ab(str) {
  const buffer = new ArrayBuffer(str.length);
  let bufferView = new Uint8Array(buffer);
  for (let i = 0; i < str.length; i++) {
      bufferView[i] = str.charCodeAt(i);
  }
  return buffer;
}

function urlSafeBase64Encode(data) {
  let base64 = typeof data === "string" ? btoa(encodeURIComponent(data).replace(/%([0-9A-F]{2})/g, (match, p1) => String.fromCharCode(parseInt("0x" + p1)))) : btoa(String.fromCharCode(...new Uint8Array(data)));
  return base64.replace(/\+/g, "-").replace(/\//g, "_").replace(/=+$/, "");
}

php

<?php

// 配置变量
$PROJECT_ID = '';
$CLIENT_EMAIL = '';
$PRIVATE_KEY = "";

// 主函数
function main() {
    global $CLIENT_EMAIL, $PRIVATE_KEY;

    $signedJWT = createSignedJWT($CLIENT_EMAIL, $PRIVATE_KEY);
    list($token, $err) = exchangeJwtForAccessToken($signedJWT);

    if ($token === null) {
        error_log("Invalid jwt token: $err");
        return createErrorResponse(500, "api_error", "invalid authentication credentials");
    }

    // 这里可以继续处理 $token
}

function createErrorResponse($status, $errorType, $message) {
    $errorObject = ['type' => 'error', 'error' => ['type' => $errorType, 'message' => $message]];
    http_response_code($status);
    header('Content-Type: application/json');
    header('Access-Control-Allow-Origin: *');
    echo json_encode($errorObject);
}

function createSignedJWT($email, $pkey) {
    $pkey = preg_replace('/-----BEGIN PRIVATE KEY-----|-----END PRIVATE KEY-----|\r|\n|\\n/', '', $pkey);
    $privateKey = openssl_pkey_get_private(base64_decode($pkey));

    if (!$privateKey) {
        throw new Exception("Failed to load private key");
    }

    $authUrl = "https://www.googleapis.com/oauth2/v4/token";
    $issued = time();
    $expires = $issued + 600;

    $header = [
        'alg' => 'RS256',
        'typ' => 'JWT'
    ];

    $payload = [
        'iss' => $email,
        'aud' => $authUrl,
        'iat' => $issued,
        'exp' => $expires,
        'scope' => 'https://www.googleapis.com/auth/cloud-platform'
    ];

    $encodedHeader = urlSafeBase64Encode(json_encode($header));
    $encodedPayload = urlSafeBase64Encode(json_encode($payload));

    $unsignedToken = "$encodedHeader.$encodedPayload";

    openssl_sign($unsignedToken, $signature, $privateKey, OPENSSL_ALGO_SHA256);

    $encodedSignature = urlSafeBase64Encode($signature);
    return "$unsignedToken.$encodedSignature";
}

function exchangeJwtForAccessToken($signed_jwt) {
    $auth_url = "https://www.googleapis.com/oauth2/v4/token";
    $params = [
        'grant_type' => 'urn:ietf:params:oauth:grant-type:jwt-bearer',
        'assertion' => $signed_jwt
    ];

    $options = [
        'http' => [
            'header'  => "Content-type: application/x-www-form-urlencoded\r\n",
            'method'  => 'POST',
            'content' => http_build_query($params)
        ]
    ];

    $context  = stream_context_create($options);
    $result = file_get_contents($auth_url, false, $context);

    if ($result === FALSE) {
        return [null, "Failed to get access token"];
    }

    $r = json_decode($result, true);

    if (isset($r['access_token'])) {
        return [$r['access_token'], ""];
    }

    return [null, json_encode($r)];
}

function urlSafeBase64Encode($data) {
    $base64 = base64_encode($data);
    return str_replace(['+', '/', '='], ['-', '_', ''], $base64);
}

// 调用主函数
main();

?>

网友回复

我知道答案,我要回答