Google Identity Services 程式庫可讓使用者透過瀏覽器的彈出式視窗或重新導向使用者體驗流程,向 Google 索取授權碼。這會啟動安全的 OAuth 2.0 流程,並產生存取權杖,用於代表使用者呼叫 Google API。
OAuth 2.0 授權碼流程摘要:
- 透過瀏覽器,使用者 (Google 帳戶擁有者) 透過按鈕點選等手勢,向 Google 要求授權碼。
- Google 會回應,將專屬授權碼傳送至在使用者瀏覽器中執行的 JavaScript 網頁應用程式中回呼,或直接使用瀏覽器重新導向來叫用授權碼端點。
- 您的後端平台會代管授權碼端點並接收該代碼。驗證完成後,系統會使用對 Google 符記端點提出要求,以交換每個使用者的存取權和更新權杖。
- Google 會驗證授權碼、確認要求來自安全平台、核發存取權和更新權杖,並透過呼叫平台代管的登入端點傳回權杖。
- 您的登入端點會接收存取權杖和更新權杖,並安全地儲存更新權杖,以利日後使用。
必要條件
請按照「設定」一節所述步驟設定 OAuth 同意畫面、取得用戶端 ID,然後載入用戶端程式庫。
初始化程式碼用戶端
google.accounts.oauth2.initCodeClient()
方法會初始化程式碼用戶端。
彈出式視窗或重新導向模式
您可以選擇使用重新導向或彈出式模式使用者流程來分享授權碼。在重新導向模式中,您會在伺服器上代管 OAuth2 授權端點,而 Google 會將使用者代理程式重新導向至這個端點,並將驗證碼分享為網址參數。針對彈出式模式,您必須定義 JavaScript 回呼處理常式,以便將授權碼傳送至伺服器。您可以使用彈出式視窗模式,讓訪客不必離開網站,即可享有流暢的使用者體驗。
如要初始化下列項目的用戶端:
重新導向使用者體驗流程,將
ux_mode
設為redirect
,並將redirect_uri
的值設為平台的授權碼端點。這個值必須與您在 API 控制台中設定的 OAuth 2.0 用戶端的授權重新導向 URI 完全相符。也必須符合 Redirect URI 驗證規則。彈出式使用者體驗流程,將
ux_mode
設為popup
,並將callback
的值設為您用來將授權碼傳送至平台的函式名稱。
防範 CSRF 攻擊
為了避免跨網站要求偽造 (CSRF) 攻擊,我們在重新導向和彈出式視窗模式的使用者體驗流程中採用了略有不同的技術。在重新導向模式中,系統會使用 OAuth 2.0 state 參數。如要進一步瞭解如何產生及驗證 state 參數,請參閱 RFC6749 10.12 節:跨網站要求偽造。在彈出式模式中,您可以將自訂 HTTP 標頭新增至要求,然後在伺服器上確認該標頭是否符合預期的值和來源。
選擇 UX 模式,查看顯示驗證碼和 CSRF 處理程序的程式碼片段:
重新導向模式
初始化用戶端,讓 Google 將使用者的瀏覽器重新導向至驗證端點,並將驗證碼做為網址參數分享。
const client = google.accounts.oauth2.initCodeClient({
client_id: 'YOUR_GOOGLE_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
ux_mode: 'redirect',
redirect_uri: "https://your.domain/code_callback_endpoint",
state: "YOUR_BINDING_VALUE"
});
彈出式模式
初始化用戶端,讓使用者的瀏覽器接收 Google 傳送的驗證碼,並將其傳送至您的伺服器。
const client = google.accounts.oauth2.initCodeClient({
client_id: 'YOUR_GOOGLE_CLIENT_ID',
scope: 'https://www.googleapis.com/auth/calendar.readonly',
ux_mode: 'popup',
callback: (response) => {
const xhr = new XMLHttpRequest();
xhr.open('POST', code_receiver_uri, true);
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
// Set custom header for CRSF
xhr.setRequestHeader('X-Requested-With', 'XmlHttpRequest');
xhr.onload = function() {
console.log('Auth code response: ' + xhr.responseText);
};
xhr.send('code=' + response.code);
},
});
觸發 OAuth 2.0 授權碼流程
呼叫程式碼用戶端的 requestCode()
方法,觸發使用者流程:
<button onclick="client.requestCode();">Authorize with Google</button>
使用者必須先登入 Google 帳戶,並同意分享個別範圍,才能將授權碼傳回至重新導向端點或回呼處理常式。
驗證碼處理
Google 會為每位使用者產生專屬授權碼,您可以在後端伺服器上接收及驗證這組授權碼。
在彈出式模式中,callback
指定的處理常式會在使用者的瀏覽器中執行,將授權碼轉送至平台代管的端點。
在重新導向模式中,系統會將 GET
要求傳送至 redirect_url
指定的端點,並在網址 code 參數中分享授權碼。如要取得授權碼,請按照下列步驟操作:
如果您尚未實作,請建立新的授權端點;
更新現有端點,以便接受
GET
要求和網址參數。先前,我們會使用PUT
要求,其中酬載中含有授權碼值。
授權端點
您的授權碼端點必須使用下列網址查詢字串參數處理 GET
要求:
名稱 | 值 |
---|---|
authuser | 要求使用者登入驗證 |
程式碼 | Google 產生的 OAuth2 授權碼 |
HD 高畫質 | 使用者帳戶的代管網域 |
提示 | 使用者同意聲明對話方塊 |
範圍 | 以空格分隔的清單,其中包含一或多個要授權的 OAuth2 範圍 |
州 | CRSF 狀態變數 |
範例 GET
要求含有網址參數,且端點名稱為 auth-code,由 example.com 代管:
Request URL: https://www.example.com/auth-code?state=42a7bd822fe32cc56&code=4/0AX4XfWiAvnXLqxlckFUVao8j0zvZUJ06AMgr-n0vSPotHWcn9p-zHCjqwr47KHS_vDvu8w&scope=email%20profile%20https://www.googleapis.com/auth/calendar.readonly%20https://www.googleapis.com/auth/photoslibrary.readonly%20https://www.googleapis.com/auth/contacts.readonly%20openid%20https://www.googleapis.com/auth/userinfo.email%20https://www.googleapis.com/auth/userinfo.profile&authuser=0&hd=example.com&prompt=consent
如果授權碼流程是由舊版 JavaScript 程式庫啟動,或是直接呼叫 Google OAuth 2.0 端點,就會使用 POST
要求。
範例 POST
要求,其中 HTTP 要求主體中的酬載包含授權碼:
Request URL: https://www.example.com/auth-code
Request Payload: 4/0AX4XfWhll-BMV82wi4YwbrSaTPaRpUGpKqJ4zBxQldU\_70cnIdh-GJOBZlyHU3MNcz4qaw
驗證要求
請在伺服器上執行下列操作,以避免 CSRF 攻擊。
檢查 state 參數的值,以便進行重新導向。
確認 X-Requested-With: XmlHttpRequest
標頭已設為彈出式模式。
接著,您必須先成功驗證驗證碼要求,才能繼續從 Google 取得重新整理和存取權杖。
取得存取權和更新權杖
後端平台收到 Google 的授權碼並驗證要求後,請使用授權碼從 Google 取得存取和更新權杖,以便發出 API 呼叫。
請按照指示操作,從「針對網路伺服器應用程式使用 OAuth 2.0」指南的「步驟 5:將授權碼換成重新整理和存取權杖」開始。
管理符記
您的平台會安全地儲存重新整理權杖。在使用者帳戶遭到移除,或使用者同意授權遭到撤銷時,刪除儲存的重新整理權杖,方法是透過 google.accounts.oauth2.revoke
或直接透過 https://myaccount.google.com/permissions。
您也可以考慮使用 RISC,透過跨帳戶保護功能保護使用者帳戶。
一般來說,後端平台會使用存取權杖呼叫 Google API。如果您的網頁應用程式也會從使用者的瀏覽器直接呼叫 Google API,您必須實作一種方法,與您的網頁應用程式共用存取權杖,但這超出本指南的範圍。採用這種做法並使用 適用於 JavaScript 的 Google API 用戶端程式庫時,請使用 gapi.client.SetToken()
在瀏覽器記憶體中暫時儲存存取權權杖,並啟用程式庫來呼叫 Google API。