注意事項:Google 地圖平台付費方案不再開放註冊或提供給新客戶。
選擇驗證方法
如要使用 Google 地圖平台,您必須使用 API 金鑰或是用戶端 ID,搭配數位簽章來驗證要求。
可選用的驗證方法取決於您的授權類型:
在判斷要採用哪種驗證方法時,您可以考量下列這幾點:
- 使用 API 金鑰進行驗證 (付費方案)
如果使用 API 金鑰來驗證要求,您可以:- 在 Google Cloud Console 的「API」頁面管理所有的 API。
- 在 Cloud Console 的「API」頁面查看即時使用資料和 30 天的歷來使用資料。
- 將
channel
參數加進要求中,以便查看更詳細的使用情況報表。 - 透過 Google Cloud Console 查看內含超過 30 天資料的使用情況報表。
- 使用用戶端 ID 和數位簽章進行驗證 (付費方案或舊版授權)
如果使用用戶端 ID 和數位簽章來驗證要求,您可以:- 將
channel
參數加進要求中,以便查看更詳細的使用情況報表。 - 透過 Cloud Console 查看內含超過 30 天資料的使用情況報表。
- 使用 Maps JavaScript API 適用的地圖 Analytics (分析) 工具。
- 將
進一步瞭解付費方案客戶可用的報表。
使用 API 金鑰進行驗證
取得 API 金鑰
API 金鑰是一組專屬 ID,用來驗證與專案相關的使用權限與帳單處理要求。
取得 API 金鑰的方法如下:
-
在 Cloud Console 的專案選取器頁面中,選取或建立您想新增 API 金鑰的 Google Cloud 專案。
注意事項:如要使用方案的完整功能,付費客戶應使用與付費帳戶連結的專案。購買授權後,您會收到以下列格式編寫的付費資產名稱:
gme-[company] > proj-[number] ([type])
。為確保您存取的是正確的專案,請透過 console.cloud.google.com/project/number
(將number
替換成專案編號) 以「專案擁有者身分」登入 Cloud Console。 您可以在歡迎信中查看專案擁有者是誰。 -
前往「Google 地圖平台」>「憑證」頁面。
-
在「憑證」頁面上,按一下 [建立憑證] > [API 金鑰]。
「建立的 API 金鑰」對話方塊會顯示您新建立的 API 金鑰。 -
按一下 [關閉]。
新建立的 API 金鑰便會出現在「憑證」頁面的「API 金鑰」下方。
(在實際工作環境中使用新建立的金鑰前,記得要先限制 API 金鑰。)
將 API 金鑰加進要求中
每個 Google 地圖平台要求都必須包含 API 金鑰。請將以下範例中的 YOUR_API_KEY
替換成您的 API 金鑰。
https://maps.googleapis.com/maps/api/elevation/json?locations=39.7391536,-104.9847034&key=YOUR_API_KEY
使用 API 金鑰的要求必須透過 HTTPS 傳送,而對於使用用戶端 ID 的要求,則不強制但建議採用 HTTPS。此外,應用程式要求如果含有敏感的使用者資料 (如使用者所在位置),也必須採用 HTTPS。
限制 API 金鑰
限制 API 金鑰可確保只有經授權的要求才能使用 API 金鑰,進而提升您應用程式的安全性。我們極力建議您按照操作說明設定 API 金鑰的限制。詳情請參閱 API 安全性最佳做法。
限制 API 金鑰的方法如下:
-
前往「Google 地圖平台」>「憑證」頁面。
- 選取您要設定限制的 API 金鑰。畫面隨即顯示 API 金鑰屬性頁面。
- 在「金鑰限制」下方,設定下列限制:
- 應用程式限制:
- 如要接受來自您提供的清單中網路伺服器 IP 位址提出的要求,請從「應用程式限制」清單中選取 [IP 位址 (網路伺服器和 Cron 工作等)]。
- 指定一個 IPv4 或 IPv6 位址,或是採用 CIDR 標記法的子網路 (例如 192.168.0.0/22)。如果您還需要輸入其他項目,系統會在您新增上述項目後顯示新的對話方塊。
- API 限制:
- 按一下 [限制金鑰]。
- 從「選取 API」下拉式選單中選取 [Google 地圖平台]。 如果選單未列出 Google 地圖平台,您必須先加以啟用。
- 如要完成變更,請按一下 [儲存]。
使用用戶端 ID 搭配數位簽章進行驗證
購買 Google 地圖平台付費方案授權後,您會收到 Google 寄送的歡迎電子郵件,內含您的用戶端 ID 及私人加密編譯金鑰 (可用來產生您專屬的數位簽章)。
您必須將用戶端 ID 與專屬數位簽章傳遞給以下程式碼範例中的 client
和 signature
參數。
https://maps.googleapis.com/maps/api/elevation/json ?locations=39.7391536,-104.9847034 &client=YOUR_CLIENT_ID &signature=SIGNATURE
-
將
YOUR_CLIENT_ID
替換成歡迎電子郵件中隨附的用戶端 ID。您的用戶端 ID 會以 gme- 字元開頭。
-
將
SIGNATURE
替換成您專屬的數位簽章 (請參閱產生數位簽章)。
注意事項:
-
使用用戶端 ID 搭配數位簽章驗證 Google 地圖平台時,您也可以選擇使用
channel
參數接收詳細的使用報表。詳情請參閱付費方案報表簡介。 -
如果您原先使用 API 金鑰進行驗證,但現在要改用用戶端 ID,必須將要求中的
key
參數移除。Google Maps API 網路服務會拒絕同時使用用戶端 ID 與 API 金鑰送出的要求。
產生數位簽章
Google 地圖平台付費方案客戶向 Elevation API 送出要求時,必須提供數位 signature
。透過歡迎電子郵件中隨附的私人加密編譯金鑰即可產生這個簽章 (詳情請見「進一步瞭解私人加密編譯金鑰」一節的說明)。
請按照下列步驟為您的要求產生數位簽章。
-
建立不含簽章的要求網址,並務必加上
client
參數。請注意,所有非標準字元都需要經過網址編碼處理:https://maps.googleapis.com/maps/api/elevation/json?locations=39.7391536,-104.9847034&client=clientID
注意事項:所有 Google 服務都要求採用 UTF-8 字元編碼 (也就是以隱含方式納入 ASCII)。如果您的應用程式運作時會使用其他字元集,請確認網址是以 UTF-8 字元建立,且經過妥善的網址編碼處理。
-
去除要求中的網域部分,只留下路徑及查詢:
/maps/api/elevation/json?locations=39.7391536,-104.9847034&client=clientID
-
擷取您的私密金鑰 (該金鑰是以網址適用的修改版 Base64 進行編碼),並使用 HMAC-SHA1 演算法簽署前個步驟產生的網址。您可能需要將此金鑰解碼為原始的二進位格式。請注意,在大部分的加密編譯程式庫中,最終的簽章是採用二進位格式。
注意事項:修改版 Base64 網址編碼會將標準 Base64 編碼的
+
及/
字元分別替換成-
和_
,因此這類 Base64 簽章不需要再進行網址編碼處理。 -
使用網址適用的修改版 Base64 為產生的二進位簽章進行編碼,將此簽章轉換為可在網址內傳送的物件。
-
將此簽章附加至網址 (置於
signature
參數內):https://maps.googleapis.com/maps/api/elevation/json?locations=39.7391536,-104.9847034&client=clientID&signature=base64signature
注意事項:
- 我們的伺服器會藉由專屬簽章,驗證是否所有使用您用戶端 ID 產生要求的網站都已獲得授權。此外,每個網址也都有專屬簽章,確保只有在已要求產生新簽章的情況下,才能修改使用您用戶端 ID 的要求。
- 如果嘗試以無效的簽章存取 Elevation API,就會發生
HTTP 403
(禁止) 錯誤。如要讓應用程式改用網址簽署,請務必先進行測試,確保簽章可發出有效的要求。請先測試原始網址是否有效,以及是否可以產生正確的簽章。 - 如需使用伺服器端程式碼導入網址簽署的做法範例,請參閱「網址簽署的程式碼範例」。
如要立即簽署網址,請在下方輸入網址和網址簽署密鑰。網址必須採用前文步驟 1 所述的格式,並且經過網址編碼處理。
網址簽署程式碼範例
後續章節會說明使用伺服器端程式碼導入網址簽署的方式。網址應一律在伺服器端簽署,以避免向其他使用者暴露您的加密編譯金鑰。
Python
以下範例使用標準 Python 程式庫簽署網址 (下載程式碼)。
#!/usr/bin/python # -*- coding: utf-8 -*- """ Signs a URL using a URL signing secret """ import hashlib import hmac import base64 import urllib.parse as 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, str.encode(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.decode() if __name__ == "__main__": input_url = input("URL to Sign: ") secret = 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; } }
Node JS
以下範例使用原生 Node 模組簽署網址 (下載程式碼)。
'use strict' const crypto = require('crypto'); const url = require('url'); /** * Convert from 'web safe' base64 to true base64. * * @param {string} safeEncodedString The code you want to translate * from a web safe form. * @return {string} */ function removeWebSafe(safeEncodedString) { return safeEncodedString.replace(/-/g, '+').replace(/_/g, '/'); } /** * Convert from true base64 to 'web safe' base64 * * @param {string} encodedString The code you want to translate to a * web safe form. * @return {string} */ function makeWebSafe(encodedString) { return encodedString.replace(/\+/g, '-').replace(/\//g, '_'); } /** * Takes a base64 code and decodes it. * * @param {string} code The encoded data. * @return {string} */ function decodeBase64Hash(code) { // "new Buffer(...)" is deprecated. Use Buffer.from if it exists. return Buffer.from ? Buffer.from(code, 'base64') : new Buffer(code, 'base64'); } /** * Takes a key and signs the data with it. * * @param {string} key Your unique secret key. * @param {string} data The url to sign. * @return {string} */ function encodeBase64Hash(key, data) { return crypto.createHmac('sha1', key).update(data).digest('base64'); } /** * Sign a URL using a secret key. * * @param {string} path The url you want to sign. * @param {string} secret Your unique secret key. * @return {string} */ function sign(path, secret) { const uri = url.parse(path); const safeSecret = decodeBase64Hash(removeWebSafe(secret)); const hashedSignature = makeWebSafe(encodeBase64Hash(safeSecret, uri.path)); return url.format(uri) + '&signature=' + hashedSignature; }
C#
以下範例使用預設的 System.Security.Cryptography
程式庫簽署網址要求。請注意,我們必須轉換預設的 Base64 編碼,才能導入安全網址版本 (下載程式碼)。
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)); } } }
針對測試部分,您可以試試看以下網址及私密金鑰能否產生正確的簽章。請注意,這組私密金鑰僅供測試,實際上無法通過任何 Google 服務的驗證。
- 網址:
https://maps.googleapis.com/maps/api/geocode/json?address=New+York&client=clientID
- 私密金鑰:
vNIXE0xscrmjlyV-12Nj_BvUPaw=
- 要簽署的網址部分:
/maps/api/geocode/json?address=New+York&client=clientID
- 簽章:
chaRF2hTJKOScPr-RQCEhZbSzIE=
- 完整的已簽署網址:
https://maps.googleapis.com/maps/api/geocode/json?address=New+York&client=clientID&signature=chaRF2hTJKOScPr-RQCEhZbSzIE=
其他程式語言範例
如需其他程式語言範例,請參閱網址簽署專案。
進一步瞭解私人加密編譯金鑰
系統會使用您的用戶端 ID 核發私人加密編譯網址簽署金鑰,該金鑰是您和 Google 之間的「共同密鑰」。這組簽署金鑰為您獨有,且專屬於您的用戶端 ID。因此,請妥善保管簽署金鑰。這組金鑰不得用於任何要求、儲存在任何網站上,或張貼到任何公開論壇;否則凡是能取得該簽署金鑰的使用者,都可以假冒您的身分提出要求。
注意事項:這組私人加密編譯簽署金鑰與 Google Cloud Console 核發的 API 金鑰「不」一樣。
如果您遺失了私人加密編譯金鑰,請登入 Cloud Console,然後按一下 [地圖:管理用戶端 ID] 以擷取該金鑰。
排解驗證相關問題
如果要求格式錯誤或提供的簽章無效,Google 地圖平台會傳回 HTTP 403 (Forbidden)
錯誤。
如要排解個別網址的問題,您可以使用網址簽署偵錯工具。此工具可以讓您快速驗證網址和應用程式產生的簽章。
除了上述方法外,付費方案客戶也可以登入 Cloud Console,然後選取 [資源] > [Google 地圖平台付費方案線上工具] > [網路服務和 Image API 的網址簽署偵錯工具],接著解決個別網址的問題。