驗證與授權

本頁面僅適用於舊版 Maps APIs for Work 或 Maps API for Business 授權的客戶。本頁面不適用於 2016 年 1 月推出之新版 Google Maps APIs Premium Plan 的客戶。

用戶端編號與簽章

搭配 Google Maps APIs for Work 授權使用 Google Maps APIs Web 服務 時,需要兩種驗證參數:用戶端編號與唯一數位簽章 (而非 API 金鑰)。

如果您是從免費 API Web 服務切換至 Google Maps APIs for Work 實作,您必須從要求中移除 key 參數。Google Maps APIs Web 服務將拒絕同時以用戶端編號和金鑰做出的要求

您的用戶端編號與簽章

購買 Google Maps APIs for Work 授權時,您會收到 Google 寄來的歡迎電子郵件,當中包含您的用戶端編號私密密碼編譯金鑰

  • 您的用戶端編號用於存取 Google Maps APIs for Work 的特殊功能;存取任何 API 程式庫或服務時,您必須提供用戶端編號。所有用戶端編號皆以 gme- 前置詞為開頭。請將用戶端編號以 client 參數的值傳遞。

  • 使用您的私密密碼編譯金鑰產生唯一數位簽章。請將此簽章以 signature 參數的值傳遞。您可以在下方的數位簽章一節取得更多關於產生簽章的資訊。

針對 Google Maps Directions API 的範例如下:

    https://maps.googleapis.com/maps/api/directions/json
      ?origin=Toronto
      &destination=Montreal
      &client=gme-YOUR_CLIENT_ID
      &signature=YOUR_URL_SIGNATURE

如果您遺失了用戶端編號或私密密碼編譯金鑰,您可以登入 Google Cloud Support Portal,並從頁面左方的連結中按一下 [Maps:Manage Client ID] 來將其取回。

針對報告的選擇性參數

除了驗證參數外,下列參數可以選擇性地與 Google Maps APIs for Work 要求搭配使用:

  • channel 可在報告中將不同管道分組,用於提供額外的報告詳細資料。請參閱 Google Maps APIs for Work Web 服務配額與報告文件中的管道報告一節。

數位簽章

Google Maps APIs for Work 客戶對 Web 服務 API 提出要求時,必須要有使用歡迎電子郵件中提供的私密密碼編譯金鑰產生的數位 signature

簽署程序會使用加密演算法,來結合一組 URL 和金鑰。所產生的唯一簽章可讓我們的伺服器驗證使用您用戶端編號產生要求的所有網站,是否擁有正確的授權。每個 URL 的簽章均不同,這可確保在尚未要求產生新簽章的情況下,無法對使用您用戶端編號的要求進行修改。

您的私密密碼編譯金鑰

您的私密密碼編譯 URL 簽署金鑰會與用戶端編號一同核發,且是您與 Google 之間的「秘密共用金鑰」。此簽署金鑰僅屬於您個人,且是您用戶端編號所獨有。因此,請妥善保管您的簽署金鑰。請務必不要在任何要求中傳遞此金鑰、在任何網站上儲存金鑰,或將金鑰張貼至任何公開論壇。只要取得此簽署金鑰,任何人都可以用您的身分詐騙要求。

注意:此私密密碼編譯簽署金鑰和 Google API Console 所發的 API 金鑰不同

如果您遺失了私密密碼編譯金鑰,請登入 Google Cloud Support Portal 並按一下 [Maps:Manage Client ID] 來取回金鑰。

產生數位簽章

嘗試以無效簽章存取 Google Maps APIs Web 服務將造成 HTTP 403 (禁止)錯誤。將應用程式轉換為使用 URL 簽署時,請務必測試您的簽章,以確保其能起始有效的要求。您應先測試原始 URL 是否有效,並測試您是否已產生正確的簽章。

依照這些步驟為您的要求建立數位簽章:

  1. 不使用簽章建構要求 URL 時,請務必納入您的 client 參數。請注意,所有非標準字元皆需以網址編碼。例如,針對 Directions API,請用下列方式建構網址:

    https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&client=clientID

    注意:所有 Google 服務都需要 UTF-8 字元編碼(以隱含方式包括 ASCII)。如果您的應用程式使用其他字元集運作,務必使用 UTF-8 來建構 URL 並正確地以 URL 編碼。

  2. 剔除要求的網域部分,只留下路徑與查詢。例如,針對 Directions API:

    /maps/api/directions/json?origin=Toronto&destination=Montreal&client=clientID

  3. 擷取您的私密金鑰(此金鑰是以適用於 URL 的改進 Base64 編碼),並使用 HMAC-SHA1 演算法簽署上述 URL。您可能需要將此金鑰解碼為其原始二進位格式。請注意,在大部分的密碼編譯程式庫中,產生的簽章都是二進位格式。

    注意:適用於 URL 的改進 Base64 會將標準 Base64 的 +/ 字元分別以 -_ 取代,使這些 Base64 簽章不再需要以 URL 編碼。

  4. 使用適用於 URL 的改進 Base64 將產生的二進位簽章編碼,轉換此簽章以供在 URL 內傳遞。

  5. signature 參數中,將此簽章附加到網址。例如,針對 Directions API:

    https://maps.googleapis.com/maps/api/directions/json?origin=Toronto&destination=Montreal&client=clientID&signature=base64signature

請參閱 URL 簽署範例程式碼來取得使用伺服器端程式碼實作 URL 簽署的範例。

URL 簽署的範例程式碼

以下各節說明使用伺服器端程式碼實作 URL 簽署的方式。URL 一律必須在伺服器端簽署,以免向使用者公開您的密碼編譯金鑰。

Python

下面的範例使用標準 Python 程式庫來簽署 URL。(下載程式碼)。

#!/usr/bin/python
# -*- coding: utf-8 -*-
""" Signs a URL using a URL signing secret """

import hashlib
import hmac
import base64
import urlparse

def sign_url(input_url=None, secret=None):
  """ Sign a request URL with a URL signing secret.

      Usage:
      from urlsigner import sign_url

      signed_url = sign_url(input_url=my_url, secret=SECRET)

      Args:
      input_url - The URL to sign
      secret    - Your URL signing secret

      Returns:
      The signed request URL
  """

  if not input_url or not secret:
    raise Exception("Both input_url and secret are required")

  url = urlparse.urlparse(input_url)

  # We only need to sign the path+query part of the string
  url_to_sign = url.path + "?" + url.query

  # Decode the private key into its binary format
  # We need to decode the URL-encoded private key
  decoded_key = base64.urlsafe_b64decode(secret)

  # Create a signature using the private key and the URL-encoded
  # string using HMAC SHA1. This signature will be binary.
  signature = hmac.new(decoded_key, url_to_sign, hashlib.sha1)

  # Encode the binary signature into base64 for use within a URL
  encoded_signature = base64.urlsafe_b64encode(signature.digest())

  original_url = url.scheme + "://" + url.netloc + url.path + "?" + url.query

  # Return signed URL
  return original_url + "&signature=" + encoded_signature

if __name__ == "__main__":
  input_url = raw_input("URL to Sign: ")
  secret = raw_input("URL signing secret: ")
  print "Signed URL: " + sign_url(input_url, secret)

Java

下面的範例使用自 JDK 1.8 起提供的 java.util.Base64 類別 - 舊版需要使用 Apache Commons 或類似程式碼。(下載程式碼)。

import java.io.IOException;
import java.io.UnsupportedEncodingException;
import java.net.URI;
import java.net.URISyntaxException;
import java.security.InvalidKeyException;
import java.security.NoSuchAlgorithmException;
import java.util.Base64;  // JDK 1.8 only - older versions may need to use Apache Commons or similar.
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.net.URL;
import java.io.BufferedReader;
import java.io.InputStreamReader;

public class UrlSigner {

  // Note: Generally, you should store your private key someplace safe
  // and read them into your code

  private static String keyString = "YOUR_PRIVATE_KEY";
  
  // The URL shown in these examples is a static URL which should already
  // be URL-encoded. In practice, you will likely have code
  // which assembles your URL from user or web service input
  // and plugs those values into its parameters.
  private static String urlString = "YOUR_URL_TO_SIGN";

  // This variable stores the binary key, which is computed from the string (Base64) key
  private static byte[] key;
  
  public static void main(String[] args) throws IOException,
    InvalidKeyException, NoSuchAlgorithmException, URISyntaxException {
    
    BufferedReader input = new BufferedReader(new InputStreamReader(System.in));
    
    String inputUrl, inputKey = null;

    // For testing purposes, allow user input for the URL.
    // If no input is entered, use the static URL defined above.    
    System.out.println("Enter the URL (must be URL-encoded) to sign: ");
    inputUrl = input.readLine();
    if (inputUrl.equals("")) {
      inputUrl = urlString;
    }
    
    // Convert the string to a URL so we can parse it
    URL url = new URL(inputUrl);
 
    // For testing purposes, allow user input for the private key.
    // If no input is entered, use the static key defined above.   
    System.out.println("Enter the Private key to sign the URL: ");
    inputKey = input.readLine();
    if (inputKey.equals("")) {
      inputKey = keyString;
    }
    
    UrlSigner signer = new UrlSigner(inputKey);
    String request = signer.signRequest(url.getPath(),url.getQuery());
    
    System.out.println("Signed URL :" + url.getProtocol() + "://" + url.getHost() + request);
  }
  
  public UrlSigner(String keyString) throws IOException {
    // Convert the key from 'web safe' base 64 to binary
    keyString = keyString.replace('-', '+');
    keyString = keyString.replace('_', '/');
    System.out.println("Key: " + keyString);
    // Base64 is JDK 1.8 only - older versions may need to use Apache Commons or similar.
    this.key = Base64.getDecoder().decode(keyString);
  }

  public String signRequest(String path, String query) throws NoSuchAlgorithmException,
    InvalidKeyException, UnsupportedEncodingException, URISyntaxException {
    
    // Retrieve the proper URL components to sign
    String resource = path + '?' + query;
    
    // Get an HMAC-SHA1 signing key from the raw key bytes
    SecretKeySpec sha1Key = new SecretKeySpec(key, "HmacSHA1");

    // Get an HMAC-SHA1 Mac instance and initialize it with the HMAC-SHA1 key
    Mac mac = Mac.getInstance("HmacSHA1");
    mac.init(sha1Key);

    // compute the binary signature for the request
    byte[] sigBytes = mac.doFinal(resource.getBytes());

    // base 64 encode the binary signature
    // Base64 is JDK 1.8 only - older versions may need to use Apache Commons or similar.
    String signature = Base64.getEncoder().encodeToString(sigBytes);
    
    // convert the signature to 'web safe' base 64
    signature = signature.replace('+', '-');
    signature = signature.replace('/', '_');
    
    return resource + "&signature=" + signature;
  }
}

C#

下面的範例使用預設 System.Security.Cryptography 程式庫來簽署 URL 要求。請注意,我們需要轉換預設的 Base64 編碼,以實作可放心使用的 URL 版本。(下載程式碼)。

using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Text.RegularExpressions;
using System.Web;

namespace SignUrl {

  public struct GoogleSignedUrl {

    public static string Sign(string url, string keyString) {
      ASCIIEncoding encoding = new ASCIIEncoding();

      // converting key to bytes will throw an exception, need to replace '-' and '_' characters first.
      string usablePrivateKey = keyString.Replace("-", "+").Replace("_", "/");
      byte[] privateKeyBytes = Convert.FromBase64String(usablePrivateKey);

      Uri uri = new Uri(url);
      byte[] encodedPathAndQueryBytes = encoding.GetBytes(uri.LocalPath + uri.Query);

      // compute the hash
      HMACSHA1 algorithm = new HMACSHA1(privateKeyBytes);
      byte[] hash = algorithm.ComputeHash(encodedPathAndQueryBytes);

      // convert the bytes to string and make url-safe by replacing '+' and '/' characters
      string signature = Convert.ToBase64String(hash).Replace("+", "-").Replace("/", "_");
            
      // Add the signature to the existing URI.
      return uri.Scheme+"://"+uri.Host+uri.LocalPath + uri.Query +"&signature=" + signature;
    }
  }

  class Program {

    static void Main() {
    
      // Note: Generally, you should store your private key someplace safe
      // and read them into your code

      const string keyString = "YOUR_PRIVATE_KEY";
  
      // The URL shown in these examples is a static URL which should already
      // be URL-encoded. In practice, you will likely have code
      // which assembles your URL from user or web service input
      // and plugs those values into its parameters.
      const  string urlString = "YOUR_URL_TO_SIGN";
      
      string inputUrl = null;
      string inputKey = null;
    
      Console.WriteLine("Enter the URL (must be URL-encoded) to sign: ");
      inputUrl = Console.ReadLine();
      if (inputUrl.Length == 0) {
        inputUrl = urlString;
      }     
    
      Console.WriteLine("Enter the Private key to sign the URL: ");
      inputKey = Console.ReadLine();
      if (inputKey.Length == 0) {
        inputKey = keyString;
      }
      
      Console.WriteLine(GoogleSignedUrl.Sign(inputUrl,inputKey));
    }
  }
}

針對測試用途,您可以測試下列 URL 及私密金鑰來確認是否能產生正確簽章。請注意,此私密金鑰僅供測試,而且不會經過任何 Google 服務的驗證。

  • URLhttps://maps.googleapis.com/maps/api/geocode/json?address=New+York&client=clientID
  • 私密金鑰vNIXE0xscrmjlyV-12Nj_BvUPaw=
  • 需簽署的 URL 部分/maps/api/geocode/json?address=New+York&client=clientID
  • 簽章chaRF2hTJKOScPr-RQCEhZbSzIE=
  • 已簽署的完整 URLhttps://maps.googleapis.com/maps/api/geocode/json?address=New+York&client=clientID&signature=chaRF2hTJKOScPr-RQCEhZbSzIE=

其他語言的範例

網址簽署專案中提供涵蓋更多語言的範例。

疑難排解驗證問題

如果您的要求格式錯誤或提供無效的簽章,Web 服務 API 會傳回 HTTP 403 (禁止) 錯誤。

如果要疑難排解個別 URL,您可以使用 URL 簽署偵錯工具。它可以讓您快速驗證 URL 與您的應用程式產生的簽章。

或者,Google Maps APIs for Work 客戶可以登入 Google Cloud Support Portal 並選擇 Resources > Google Maps online tools > URL Signing Debugger for Web Service and Image APIs 來疑難排解個別網址。