使用後端服務器進行身份驗證

如果您將Google登錄用於與後端服務器通信的應用或網站,則可能需要識別服務器上當前登錄的用戶。為了安全地執行此操作,請在用戶成功登錄後,使用HTTPS將用戶的ID令牌發送到您的服務器。然後,在服務器上,驗證ID令牌的完整性,並使用令牌中包含的用戶信息建立會話或創建新帳戶。

將ID令牌發送到您的服務器

用戶成功登錄後,獲取用戶的ID令牌:

function onSignIn(googleUser) {
  var id_token = googleUser.getAuthResponse().id_token;
  ...
}

然後,使用HTTPS POST請求將ID令牌發送到您的服務器:

var xhr = new XMLHttpRequest();
xhr.open('POST', 'https://yourbackend.example.com/tokensignin');
xhr.setRequestHeader('Content-Type', 'application/x-www-form-urlencoded');
xhr.onload = function() {
  console.log('Signed in as: ' + xhr.responseText);
};
xhr.send('idtoken=' + id_token);

驗證ID令牌的完整性

通過HTTPS POST收到ID令牌後,必須驗證令牌的完整性。要驗證令牌是否有效,請確保滿足以下條件:

  • 該ID令牌已由Google正確簽名。使用Google的公共密鑰(以JWKPEM格式提供)來驗證令牌的簽名。這些鍵會定期旋轉。檢查響應中的Cache-Control標頭,以確定何時應再次檢索它們。
  • ID令牌中aud的值等於您應用的客戶端ID之一。必須進行此檢查,以防止發布給惡意應用程序的ID令牌被用來訪問有關您應用程序後端服務器上同一用戶的數據。
  • 的值iss在ID令牌等於accounts.google.comhttps://accounts.google.com
  • ID令牌的到期時間( exp )還沒有過去。
  • 如果您只想限制您的G Suite域成員訪問,請驗證ID令牌是否具有與您的G Suite域名匹配的hd聲明。

強烈建議您使用適合平台的Google API客戶端庫或通用JWT庫,而不是編寫自己的代碼來執行這些驗證步驟。為了進行開發和調試,您可以調用我們的tokeninfo驗證端點。

使用Google API客戶端庫

建議使用Google API客戶端庫之一(例如JavaNode.jsPHPPython )在生產環境中驗證Google ID令牌。

爪哇

要在Java中驗證ID令牌,請使用GoogleIdTokenVerifier對象。例如:

import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdToken.Payload;
import com.google.api.client.googleapis.auth.oauth2.GoogleIdTokenVerifier;

...

GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
    // Specify the CLIENT_ID of the app that accesses the backend:
    .setAudience(Collections.singletonList(CLIENT_ID))
    // Or, if multiple clients access the backend:
    //.setAudience(Arrays.asList(CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3))
    .build();

// (Receive idTokenString by HTTPS POST)

GoogleIdToken idToken = verifier.verify(idTokenString);
if (idToken != null) {
  Payload payload = idToken.getPayload();

  // Print user identifier
  String userId = payload.getSubject();
  System.out.println("User ID: " + userId);

  // Get profile information from payload
  String email = payload.getEmail();
  boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
  String name = (String) payload.get("name");
  String pictureUrl = (String) payload.get("picture");
  String locale = (String) payload.get("locale");
  String familyName = (String) payload.get("family_name");
  String givenName = (String) payload.get("given_name");

  // Use or store profile information
  // ...

} else {
  System.out.println("Invalid ID token.");
}

GoogleIdTokenVerifier.verify()方法驗證JWT簽名, aud聲明, iss聲明和exp聲明。

如果您想僅限制對G Suite域成員的訪問,還可以通過檢查Payload.getHostedDomain()方法返回的域名來驗證hd聲明。

Node.js

要在Node.js中驗證ID令牌,請使用Node.js的Google身份驗證庫。安裝庫:

npm install google-auth-library --save
然後,調用verifyIdToken()函數。例如:

const {OAuth2Client} = require('google-auth-library');
const client = new OAuth2Client(CLIENT_ID);
async function verify() {
  const ticket = await client.verifyIdToken({
      idToken: token,
      audience: CLIENT_ID,  // Specify the CLIENT_ID of the app that accesses the backend
      // Or, if multiple clients access the backend:
      //[CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]
  });
  const payload = ticket.getPayload();
  const userid = payload['sub'];
  // If request specified a G Suite domain:
  // const domain = payload['hd'];
}
verify().catch(console.error);

verifyIdToken函數驗證JWT簽名, aud聲明, exp聲明和iss聲明。

如果您只想限制您的G Suite網域成員訪問,還請確認hd聲明與您的G Suite網域名稱相符。

的PHP

要在PHP中驗證ID令牌,請使用適用於PHP的Google API客戶端庫。安裝該庫(例如,使用Composer):

composer require google/apiclient
然後,調用verifyIdToken()函數。例如:

require_once 'vendor/autoload.php';

// Get $id_token via HTTPS POST.

$client = new Google_Client(['client_id' => $CLIENT_ID]);  // Specify the CLIENT_ID of the app that accesses the backend
$payload = $client->verifyIdToken($id_token);
if ($payload) {
  $userid = $payload['sub'];
  // If request specified a G Suite domain:
  //$domain = $payload['hd'];
} else {
  // Invalid ID token
}

verifyIdToken函數驗證JWT簽名, aud聲明, exp聲明和iss聲明。

如果您只想限制您的G Suite網域成員訪問,還請確認hd聲明與您的G Suite網域名稱相符。

Python

要在Python中驗證ID令牌,請使用verify_oauth2_token函數。例如:

from google.oauth2 import id_token
from google.auth.transport import requests

# (Receive token by HTTPS POST)
# ...

try:
    # Specify the CLIENT_ID of the app that accesses the backend:
    idinfo = id_token.verify_oauth2_token(token, requests.Request(), CLIENT_ID)

    # Or, if multiple clients access the backend server:
    # idinfo = id_token.verify_oauth2_token(token, requests.Request())
    # if idinfo['aud'] not in [CLIENT_ID_1, CLIENT_ID_2, CLIENT_ID_3]:
    #     raise ValueError('Could not verify audience.')

    # If auth request is from a G Suite domain:
    # if idinfo['hd'] != GSUITE_DOMAIN_NAME:
    #     raise ValueError('Wrong hosted domain.')

    # ID token is valid. Get the user's Google Account ID from the decoded token.
    userid = idinfo['sub']
except ValueError:
    # Invalid token
    pass

verify_oauth2_token函數驗證JWT簽名, aud聲明和exp聲明。您還必須通過檢查verify_oauth2_token返回的對象來驗證hd聲明(如果適用)。如果多個客戶端訪問後端服務器,請手動驗證aud聲明。

調用tokeninfo端點

驗證ID令牌簽名以進行調試的一種簡單方法是使用tokeninfo端點。調用此終結點涉及一個額外的網絡請求,該請求會在您用自己的代碼測試正確的驗證和有效載荷提取時為您執行大部分驗證。它不適合在生產代碼中使用,因為請求可能受到限制,否則可能會出現間歇性錯誤。

要使用tokeninfo端點驗證ID令牌,請tokeninfo端點發出HTTPS POST或GET請求,然後在id_token參數中傳遞您的ID令牌。例如,要驗證令牌“ XYZ123”,請發出以下GET請求:

https://oauth2.googleapis.com/tokeninfo?id_token=XYZ123

如果令牌已正確簽名,並且issexp聲明具有期望的值,您將獲得HTTP 200響應,其中正文包含JSON格式的ID令牌聲明。這是一個示例響應:

{
 // These six fields are included in all Google ID Tokens.
 "iss": "https://accounts.google.com",
 "sub": "110169484474386276334",
 "azp": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "aud": "1008719970978-hb24n2dstb40o45d4feuo2ukqmcc6381.apps.googleusercontent.com",
 "iat": "1433978353",
 "exp": "1433981953",

 // These seven fields are only included when the user has granted the "profile" and
 // "email" OAuth scopes to the application.
 "email": "testuser@gmail.com",
 "email_verified": "true",
 "name" : "Test User",
 "picture": "https://lh4.googleusercontent.com/-kYgzyAWpZzJ/ABCDEFGHI/AAAJKLMNOP/tIXL9Ir44LE/s99-c/photo.jpg",
 "given_name": "Test",
 "family_name": "User",
 "locale": "en"
}

如果您是G Suite客戶,則可能對hd聲明感興趣,該聲明表明了用戶的託管域。這可用於將對資源的訪問限制為僅某些域的成員。缺少此聲明表明該用戶不屬於G Suite託管域。

創建一個帳戶或會話

驗證令牌後,請檢查用戶是否已在用戶數據庫中。如果是這樣,請為用戶建立一個經過身份驗證的會話。如果該用戶尚未在您的用戶數據庫中,請根據ID令牌有效負載中的信息創建新的用戶記錄,並為該用戶建立會話。當您在應用中檢測到新創建的用戶時,可以提示用戶提供所需的其他任何個人資料信息。

使用跨帳戶保護保護用戶的帳戶安全

當您依靠Google登錄用戶時,您將自動受益於Google為保護用戶數據而構建的所有安全功能和基礎架構。但是,萬一用戶的Google帳戶遭到入侵或發生其他重大安全事件(這種情況不太可能發生),您的應用也很容易受到攻擊。為了更好地保護您的帳戶免受任何重大安全事件的影響,請使用“跨帳戶保護”接收來自Google的安全警報。收到這些事件後,您可以查看用戶的Google帳戶安全性的重要變化,然後可以對服務採取措施以保護您的帳戶。