OpenID連接

Google的OpenID Connect端點已通過OpenID認證。

Google的OAuth 2.0 API可用於身份驗證和授權。本文檔介紹了我們的OAuth 2.0身份驗證實現,該實現符合OpenID Connect規範,並且已通過OpenID認證使用OAuth 2.0訪問Google API中的文檔也適用於此服務。如果您想以交互方式探索此協議,建議您使用Google OAuth 2.0 Playground 。要獲取有關Stack Overflow的幫助,請使用“ google-oauth”標記您的問題。

設置OAuth 2.0

在您的應用程序可以使用Google的OAuth 2.0身份驗證系統進行用戶登錄之前,您必須在Google API Console中設置一個項目以獲取OAuth 2.0憑據,設置重定向URI,並(可選)自定義用戶在用戶上看到的品牌信息-同意屏幕。您還可以使用API Console創建服務帳戶,啟用計費,設置過濾以及執行其他任務。有關更多詳細信息,請參見Google API Console幫助

獲取OAuth 2.0憑據

您需要OAuth 2.0憑據(包括客戶端ID和客戶端機密)來對用戶進行身份驗證並獲得對Google API的訪問權限。

To view the client ID and client secret for a given OAuth 2.0 credential, click the following text: Select credential. In the window that opens, choose your project and the credential you want, then click View.

Or, view your client ID and client secret from the Credentials page in API Console:

  1. Go to the Credentials page.
  2. Click the name of your credential or the pencil () icon. Your client ID and secret are at the top of the page.

設置重定向URI

您在API Console中設置的重定向URI決定了Google將響應發送到身份驗證請求的位置

To create, view, or edit the redirect URIs for a given OAuth 2.0 credential, do the following:

  1. Go to the Credentials page.
  2. In the OAuth 2.0 client IDs section of the page, click a credential.
  3. View or edit the redirect URIs.

If there is no OAuth 2.0 client IDs section on the Credentials page, then your project has no OAuth credentials. To create one, click Create credentials.

自定義用戶同意屏幕

對於您的用戶,OAuth 2.0身份驗證體驗包括一個同意屏幕,該屏幕描述了用戶發布的信息以及適用的條款。例如,當用戶登錄時,可能會要求他們向您的應用授予訪問其電子郵件地址和基本帳戶信息的權限。您可以使用scope參數來請求訪問此信息,該參數包含在您的應用程序的身份驗證請求中。您還可以使用範圍來請求訪問其他Google API。

用戶同意屏幕還顯示品牌信息,例如您的產品名稱,徽標和主頁URL。您可以在API Console中控製品牌信息。

要啟用項目的同意屏幕:

  1. Consent Screen page中打開Google API Console 。
  2. If prompted, select a project, or create a new one.
  3. 填寫表格,然後點擊保存

以下同意對話框顯示了當請求中同時包含OAuth 2.0和Google Drive範圍時,用戶將看到的內容。 (此通用對話框是使用Google OAuth 2.0 Playground生成的,因此它不包含將在API Console中設置的品牌信息。)

同意頁面屏幕截圖

訪問服務

Google和第三方提供了一些庫,您可以使用它們來處理實現用戶身份驗證和訪問Google API的許多實施細節。示例包括可用於各種平台的Google登錄Google客戶端庫

如果選擇不使用庫,請遵循本文檔其餘部分中的說明,該說明描述了可用庫下面的HTTP請求流。

驗證用戶

對用戶進行身份驗證涉及獲取ID令牌並對其進行驗證。 ID令牌OpenID Connect的標準化功能,旨在用於在Internet上共享身份聲明。

用於驗證用戶身份和獲取ID令牌的最常用方法稱為“服務器”流和“隱式”流。服務器流允許應用程序的後端服務器使用瀏覽器或移動設備來驗證人員的身份。當客戶端應用程序(通常是在瀏覽器中運行的JavaScript應用程序)需要直接訪問API而不是通過後端服務器訪問API時,將使用隱式流程。

本文檔介紹瞭如何執行用於驗證用戶身份的服務器流。由於在客戶端上處理和使用令牌時存在安全風險,因此隱式流程要復雜得多。如果您需要實現隱式流程,我們強烈建議您使用Google登錄

服務器流

確保在API Console中設置了應用程序,以使其能夠使用這些協議並對用戶進行身份驗證。當用戶嘗試使用Google登錄時,您需要:

  1. 創建一個防偽狀態令牌
  2. 向Google發送身份驗證請求
  3. 確認防偽狀態令牌
  4. 交換訪問令牌和ID令牌的code
  5. 從ID令牌獲取用戶信息
  6. 驗證用戶

1.創建一個防偽狀態令牌

您必須通過防止請求偽造攻擊來保護用戶的安全。第一步是創建一個唯一的會話令牌,該令牌保存應用程序與用戶客戶端之間的狀態。稍後,您將此唯一的會話令牌與Google OAuth登錄服務返回的身份驗證響應進行匹配,以驗證用戶是在發出請求,而不是惡意攻擊者。這些令牌通常稱為跨站點請求偽造( CSRF )令牌。

使用狀態令牌的一個不錯的選擇是使用高質量隨機數生成器構造一個由30個左右的字符組成的字符串。另一個是通過使用後端保密的密鑰對某些會話狀態變量進行簽名而生成的哈希。

以下代碼演示瞭如何生成唯一的會話令牌。

的PHP

您必須下載PHPGoogle API客戶端庫才能使用此示例。

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
$state = bin2hex(random_bytes(128/8));
$app['session']->set('state', $state);
// Set the client ID, token state, and application name in the HTML while
// serving it.
return $app['twig']->render('index.html', array(
    'CLIENT_ID' => CLIENT_ID,
    'STATE' => $state,
    'APPLICATION_NAME' => APPLICATION_NAME
));

爪哇

您必須下載JavaGoogle API客戶端庫才能使用此示例。

// Create a state token to prevent request forgery.
// Store it in the session for later validation.
String state = new BigInteger(130, new SecureRandom()).toString(32);
request.session().attribute("state", state);
// Read index.html into memory, and set the client ID,
// token state, and application name in the HTML before serving it.
return new Scanner(new File("index.html"), "UTF-8")
    .useDelimiter("\\A").next()
    .replaceAll("[{]{2}\\s*CLIENT_ID\\s*[}]{2}", CLIENT_ID)
    .replaceAll("[{]{2}\\s*STATE\\s*[}]{2}", state)
    .replaceAll("[{]{2}\\s*APPLICATION_NAME\\s*[}]{2}",
    APPLICATION_NAME);

Python

您必須下載適用於PythonGoogle API客戶端庫才能使用此示例。

# Create a state token to prevent request forgery.
# Store it in the session for later validation.
state = hashlib.sha256(os.urandom(1024)).hexdigest()
session['state'] = state
# Set the client ID, token state, and application name in the HTML while
# serving it.
response = make_response(
    render_template('index.html',
                    CLIENT_ID=CLIENT_ID,
                    STATE=state,
                    APPLICATION_NAME=APPLICATION_NAME))

2.向Google發送身份驗證請求

下一步是使用適當的URI參數形成HTTPS GET請求。請注意,在此過程的所有步驟中,均使用HTTPS而不是HTTP。 HTTP連接被拒絕。您應該使用authorization_endpoint元數據值從發現文檔中檢索基本URI。以下討論假定基本URI為https://accounts.google.com/o/oauth2/v2/auth

對於基本請求,請指定以下參數:

  • 從API Console Credentials page獲得的client_id
  • response_type ,它在基本授權碼流請求中應該是code 。 (有關更多信息,請response_type 。)
  • scope ,在基本請求中應為openid email 。 (有關scope更多信息,請scope 。)
  • redirect_uri應該是您服務器上的HTTP端點,它將接收來自Google的響應。該值必須與您在API Console Credentials page中配置的OAuth 2.0客戶端的授權重定向URI之一完全匹配。如果此值與授權的URI不匹配,則請求將失敗,並顯示redirect_uri_mismatch錯誤。
  • state應包含防偽唯一會話令牌的值,以及用戶返回到您的應用程序時恢復上下文所需的任何其他信息,例如起始URL。 (在state閱讀更多。)
  • nonce是您的應用程序生成的隨機值,可在存在時啟用重播保護。
  • login_hint可以是用戶的電子郵件地址或sub字符串,等效於用戶的Google ID。如果您未提供login_hint且用戶當前已登錄,則同意屏幕將包括一個批准請求,用於將用戶的電子郵件地址釋放到您的應用程序中。 (有關更多信息,請login_hint 。)
  • 使用hd參數為特定G Suite域的用戶優化OpenID Connect流。 (閱讀更多hd 。)

這是一個完整的OpenID Connect身份驗證URI的示例,帶有換行符和空格以提高可讀性:

https://accounts.google.com/o/oauth2/v2/auth?
 response_type=code&
 client_id=424911365001.apps.googleusercontent.com&
 scope=openid%20email&
 redirect_uri=https%3A//oauth2.example.com/code&
 state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foauth2-login-demo.example.com%2FmyHome&
 login_hint=jsmith@example.com&
 nonce=0394852-3190485-2490358&
 hd=example.com

如果您的應用程序請求有關用戶的任何新信息,或者如果您的應用程序請求他們先前未批准的帳戶訪問權限,則必須徵得用戶的同意。

3.確認防偽狀態令牌

響應將發送到您在請求中指定的redirect_uri 。所有響應都在查詢字符串中返回,如下所示:

https://oauth2.example.com/code?state=security_token%3D138r5719ru3e1%26url%3Dhttps%3A%2F%2Foa2cb.example.com%2FmyHome&code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&scope=openid%20email%20https://www.googleapis.com/auth/userinfo.email

在服務器上,您必須確認從Google收到的state與您在步驟1中創建的會話令牌匹配。這種往返驗證有助於確保用戶(而不是惡意腳本)正在發出請求。

以下代碼演示瞭如何確認您在步驟1中創建的會話令牌:

的PHP

您必須下載PHPGoogle API客戶端庫才能使用此示例。

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if ($request->get('state') != ($app['session']->get('state'))) {
  return new Response('Invalid state parameter', 401);
}

爪哇

您必須下載JavaGoogle API客戶端庫才能使用此示例。

// Ensure that there is no request forgery going on, and that the user
// sending us this connect request is the user that was supposed to.
if (!request.queryParams("state").equals(
    request.session().attribute("state"))) {
  response.status(401);
  return GSON.toJson("Invalid state parameter.");
}

Python

您必須下載適用於PythonGoogle API客戶端庫才能使用此示例。

# Ensure that the request is not a forgery and that the user sending
# this connect request is the expected user.
if request.args.get('state', '') != session['state']:
  response = make_response(json.dumps('Invalid state parameter.'), 401)
  response.headers['Content-Type'] = 'application/json'
  return response

4.交換訪問令牌和ID令牌的code

響應包括code參數,服務器可以交換訪問令牌和ID令牌的一次性授權代碼。您的服務器通過發送HTTPS POST請求進行此交換。 POST請求將發送到令牌端點,您應該使用token_endpoint元數據值從發現文檔中檢索該令牌端點。以下討論假定端點為https://oauth2.googleapis.com/token 。該請求必須在POST正文中包含以下參數:

領域
code初始請求返回的授權碼。
client_id您從API Console Credentials page獲得的客戶端ID,如獲得OAuth 2.0憑證中所述
client_secret您從API Console Credentials page獲得的客戶端密鑰,如獲得OAuth 2.0憑據中所述
redirect_uri針對API Console Credentials page中指定的給定client_id的授權重定向URI,如設置重定向URI中所述
grant_type該字段必須包含OAuth 2.0規範中定義authorization_code值。

實際的請求可能類似於以下示例:

POST /token HTTP/1.1
Host: oauth2.googleapis.com
Content-Type: application/x-www-form-urlencoded

code=4/P7q7W91a-oMsCeLvIaQm6bTrgtp7&
client_id=your-client-id&
client_secret=your-client-secret&
redirect_uri=https%3A//oauth2.example.com/code&
grant_type=authorization_code

對此請求的成功響應在JSON數組中包含以下字段:

領域
access_token可以發送到Google API的令牌。
expires_in訪問令牌的剩餘生存時間(以秒為單位)。
id_token一個JWT ,其中包含Google進行數字簽名的有關用戶的身份信息。
scope access_token授予的訪問範圍以空格分隔,區分大小寫的字符串列表表示。
token_type標識返回的令牌的類型。此時,此字段始終具有值Bearer
refresh_token (可選的)

僅當在身份驗證請求中將access_type參數設置為offline ,此字段才存在。有關詳細信息,請參見刷新令牌

5.從ID令牌獲取用戶信息

ID令牌是JWT (JSON Web令牌),即經過密碼簽名的Base64編碼的JSON對象。通常,在使用ID令牌之前先對其進行驗證非常重要,但是由於您是通過無中介HTTPS渠道與Google直接通信,並使用客戶機密向Google進行身份驗證,因此您可以確信該令牌確實來自Google,並且有效。如果您的服務器將ID令牌傳遞給應用程序的其他組件,則其他組件在使用令牌之前先對其進行驗證非常重要。

由於大多數API庫都將驗證與解碼base64url編碼的值並解析其中的JSON的工作結合在一起,因此,當您訪問ID令牌中的聲明時,您可能最終還是要驗證令牌。

ID令牌的有效載荷

ID令牌是一個JSON對象,其中包含一組名稱/值對。這是一個示例,其格式旨在提高可讀性:

{
  "iss": "https://accounts.google.com",
  "azp": "1234987819200.apps.googleusercontent.com",
  "aud": "1234987819200.apps.googleusercontent.com",
  "sub": "10769150350006150715113082367",
  "at_hash": "HK6E_P6Dh8Y93mRNtsDB1Q",
  "hd": "example.com",
  "email": "jsmith@example.com",
  "email_verified": "true",
  "iat": 1353601026,
  "exp": 1353604926,
  "nonce": "0394852-3190485-2490358"
}

Google ID令牌可能包含以下字段(稱為Claims ):

宣稱假如描述
aud總是此ID令牌的目標受眾。它必須是您應用程序的OAuth 2.0客戶端ID之一。
exp總是到期時間,此後不得接受ID令牌。以Unix時間(整數秒)表示。
iat總是發行ID令牌的時間。以Unix時間(整數秒)表示。
iss總是響應的發行者的發行者標識符。始終https://accounts.google.comaccounts.google.com獲取Google ID令牌。
sub總是用戶的標識符,在所有Google帳戶中都是唯一的,並且從未重複使用。一個Google帳戶可以在不同的時間點具有多個電子郵件地址,但是sub值永遠不會改變。在應用程序中將sub用作用戶的唯一標識符鍵。最大長度為255個區分大小寫的ASCII字符。
at_hash訪問令牌哈希。提供驗證,以確保訪問令牌已綁定到身份令牌。如果在服務器流中向ID令牌頒發了access_token值,則始終包含此聲明。此聲明可以用作防止跨站點請求偽造攻擊的備用機制,但是,如果您按照步驟1步驟3進行操作,則不必驗證訪問令牌。
azp授權演示者的client_id 。僅當請求ID令牌的一方與ID令牌的受眾不同時才需要此聲明。對於混合應用程序,在Google上可能就是這種情況,其中Web應用程序和Android應用程序具有不同的OAuth 2.0 client_id但是共享相同的Google API項目。
email用戶的電子郵件地址。該值可能不是該用戶唯一的,因此不適合用作主鍵。僅當您的範圍包括email範圍值時才提供。
email_verified如果用戶的電子郵件地址已經過驗證,則為true;否則為true。否則為假。
family_name用戶的姓或名。存在name聲明時可能會提供。
given_name用戶的給定名稱或名字。存在name聲明時可能會提供。
hd用戶的託管G Suite域。僅當用戶屬於託管域時才提供。
locale用戶的語言環境,由BCP 47語言標記表示。存在name聲明時可能會提供。
name用戶的全名,以可顯示的形式。可能在以下情況下提供:
  • 請求範圍包括字符串“個人資料”
  • ID令牌是通過令牌刷新返回的

存在name聲明時,您可以使用它們來更新應用程序的用戶記錄。請注意,此聲明永遠不能保證存在。

nonce您的應用在身份驗證請求中提供的nonce的值。您應該通過確保僅提供一次來實施針對重放攻擊的保護。
picture用戶個人資料圖片的URL。可能在以下情況下提供:
  • 請求範圍包括字符串“個人資料”
  • ID令牌是通過令牌刷新返回的

存在picture聲明時,您可以使用它們來更新應用程序的用戶記錄。請注意,此聲明永遠不能保證存在。

profile用戶個人資料頁面的URL。可能在以下情況下提供:
  • 請求範圍包括字符串“個人資料”
  • ID令牌是通過令牌刷新返回的

如果存在profile聲明,則可以使用它們來更新應用程序的用戶記錄。請注意,此聲明永遠不能保證存在。

6.驗證用戶

從ID令牌獲取用戶信息後,您應該查詢應用程序的用戶數據庫。如果用戶已經存在於您的數據庫中,並且Google API響應滿足所有登錄要求,則應該為該用戶啟動應用程序會話。

如果用戶不在用戶數據庫中,則應將用戶重定向到新用戶註冊流程。您可能可以根據從Google收到的信息自動註冊用戶,或者至少可以預先填寫註冊表格中需要的許多字段。除了ID令牌中的信息之外,您還可以在我們的用戶個人資料端點上獲取其他用戶個人資料信息

進階主題

以下各節更詳細地介紹了Google OAuth 2.0 API。該信息適用於對身份驗證和授權具有高級要求的開發人員。

訪問其他Google API

使用OAuth 2.0進行身份驗證的優點之一是,您的應用程序可以在對用戶進行身份驗證的同時獲得代表用戶使用其他Google API的權限(例如YouTube,Google雲端硬盤,日曆或通訊錄)。為此,請在發送給Google的身份驗證請求中包括所需的其他範圍。例如,要將用戶的年齡段添加到身份驗證請求中,請傳遞openid email https://www.googleapis.com/auth/profile.agerange.read的範圍參數。在同意屏幕上會適當提示用戶。您從Google收到的訪問令牌使您可以訪問與您請求和授予的訪問範圍相關的所有API。

刷新令牌

在您的API訪問請求中,您可以請求在code交換期間返回刷新令牌。當用戶不存在於應用程序中時,刷新令牌可為您的應用程序提供對Google API的連續訪問權限。要請求刷新令牌,請在身份驗證請求中將access_type參數設置為offline

注意事項:

  • 確保安全且永久地存儲刷新令牌,因為您只能在第一次執行代碼交換流程時獲得刷新令牌。
  • 發出刷新令牌的數量有限制:每個客戶端/用戶組合一個限制,所有客戶端中每個用戶一個限制。如果您的應用程序請求太多刷新令牌,則可能會遇到這些限制,在這種情況下,較早的刷新令牌將停止工作。

有關更多信息,請參見刷新訪問令牌(離線訪問)

您可以通過將prompt參數設置為在身份驗證請求中表示consent ,來提示用戶重新授權您的應用。當包含prompt=consent時,即使您先前將所有範圍授予了您的Google API項目,每次您的應用請求訪問範圍的授權時,都會顯示同意屏幕。因此,僅在必要時才包含prompt=consent

有關prompt參數的更多信息,請參閱身份驗證URI參數表中的prompt

身份驗證URI參數

下表提供了Google OAuth 2.0身份驗證API接受的參數的更完整說明。

範圍必需的描述
client_id (必需的)您從API Console Credentials page獲得的客戶端ID字符串,如獲得OAuth 2.0憑證中所述
nonce (必需的)應用程式產生的隨機值,可啟用重播保護。
response_type (必需的)如果值為code ,則啟動基本授權代碼流,要求對令牌端點進行POST以獲取令牌。如果該值為token id_tokenid_token token ,則啟動“ 隱式”流程,要求在重定向URI上使用JavaScript來從URI #fragment標識符檢索令牌。
redirect_uri (必需的)確定將響應發送到的位置。此參數的值必須與您在API Console Credentials page中設置的授權重定向值之一完全匹配(包括HTTP或HTTPS方案,大小寫和結尾的“ /”(如果有))。
scope (必需的)

scope參數必須以openid值開頭,然後包括profile值, email值或兩者。

如果存在profile範圍值,則ID令牌可能(但不能保證)包括用戶的默認profile聲明。

如果存在email範圍值,則ID令牌包括emailemail_verified聲明。

除了這些特定於OpenID的作用域之外,您的作用域參數還可以包括其他作用域值。所有作用域值必須以空格分隔。例如,如果您希望按文件訪問用戶的Google雲端硬盤,則範圍參數可能是openid profile email https://www.googleapis.com/auth/drive.file

有關可用範圍的信息,請參閱Google API的OAuth 2.0範圍或您要使用的Google API的文檔。

state (可選,但強烈建議)

在協議中往返的不透明字符串;也就是說,它在Basic流中作為URI參數返回,在Implicit流中作為URI #fragment標識符返回。

state對於關聯請求和響應可能很有用。因為您可以猜測您的redirect_uri ,所以使用state值可以增加對傳入連接是應用程序發起的身份驗證請求的結果的保證。如果您在該state變量中生成隨機字符串或對某些客戶端狀態(例如cookie)的哈希進行編碼,則可以驗證響應以另外確保請求和響應源自同一瀏覽器。這提供了針對諸如跨站點請求偽造之類的攻擊的保護。

access_type (可選的)允許的值是offlineonline 。效果記錄在“脫機訪問”中;如果正在請求訪問令牌,則除非指定offline值,否則客戶端不會收到刷新令牌。
display (可選的) ASCII字符串值,用於指定授權服務器如何顯示認證和同意用戶界面頁面。以下值已指定並由Google服務器接受,但對其行為沒有任何影響: pagepopuptouchwap
hd (可選的)

hd (託管域)參數可簡化G Suite託管帳戶的登錄過程。通過包含G Suite用戶的域(例如, mycollege.edu ),可以指示應該為該域中的帳戶優化帳戶選擇UI。要針對一般的G Suite帳戶(而不只是一個域)進行優化,請設置一個星號( * ): hd=*

不要依賴此UI優化來控制誰可以訪問您的應用程序,因為可以修改客戶端請求。確保驗證返回的ID令牌hd聲明值與您期望的值匹配(例如mycolledge.edu )。與request參數不同,ID令牌hd聲明包含在Google的安全令牌中,因此可以信任該值。

include_granted_scopes (可選的)如果為該參數提供值true ,並且授權請求被批准,則該授權將包括先前授予該用戶/應用程序組合其他範圍的所有授權;請參閱增量授權

請注意,您無法使用已安裝的應用程序流進行增量授權。

login_hint (可選的)當您的應用知道正在嘗試認證的用戶時,它可以將此參數作為提示提供給認證服務器。傳遞此提示會抑制帳戶選擇器,並預先填寫登錄表單上的電子郵件框,或者選擇適當的會話(如果用戶使用多次登錄),這可以幫助您避免在您的應用中出現問題登錄錯誤的用戶帳戶。該值可以是電子郵件地址,也可以是sub字符串,與用戶的Google ID等效。
prompt (可選的)字符串值的空格分隔列表,用於指定授權服務器是否提示用戶進行重新認證和同意。可能的值為:
  • none

    授權服務器不顯示任何身份驗證或用戶同意屏幕;如果用戶尚未通過身份驗證,並且未針對請求的範圍進行預配置的同意,則它將返回錯誤。您可以使用none檢查現有的身份驗證和/或同意。

  • consent

    授權服務器在將信息返回給客戶端之前提示用戶同意。

  • select_account

    授權服務器提示用戶選擇用戶帳戶。這允許在授權服務器上擁有多個帳戶的用戶從他們可能具有當前會話的多個帳戶中進行選擇。

如果未指定任何值,並且用戶先前未授權訪問,則將向用戶顯示一個同意屏幕。

驗證ID令牌

您需要驗證服務器上的所有ID令牌,除非您知道它們直接來自Google。例如,您的服務器必須將其從客戶端應用收到的所有ID令牌驗證為真實。

在以下常見情況下,您可能會向服務器發送ID令牌:

  • 發送帶有需要驗證的請求的ID令牌。 ID令牌告訴您發出請求的特定用戶,以及為該客戶端授予該ID令牌的客戶端。

ID令牌很敏感,如果被攔截,可能會被濫用。您必須確保僅通過HTTPS且僅通過POST數據或在請求標頭內傳輸這些令牌,以確保安全地處理這些令牌。如果將ID令牌存儲在服務器上,則還必須安全地存儲它們。

使ID令牌有用的一件事是,您可以在應用程序的不同組件之間傳遞它們。這些組件可以將ID令牌用作輕量級身份驗證機制,以對應用程序和用戶進行身份驗證。但是,在您可以使用ID令牌中的信息或將其用作用戶已通過身份驗證的斷言之前,您必須對其進行驗證。

驗證ID令牌需要幾個步驟:

  1. 驗證ID令牌已由發行者正確簽名。 Google簽發的令牌使用在發現文檔jwks_uri元數據值中指定的URI處找到的證書之一進行簽名。
  2. 驗證ID令牌中的iss聲明的值等於https://accounts.google.comaccounts.google.com
  3. 驗證ID令牌中aud聲明的值是否等於您應用的客戶端ID。
  4. 驗證ID令牌的到期時間( exp索賠)是否還沒有過去。
  5. 如果您在請求中指定了hd參數值,請驗證ID令牌是否具有與接受的G Suite託管域匹配的hd聲明。

第2步到第5步僅涉及字符串和日期比較,這很簡單,因此在此不再詳細介紹。

第一步更加複雜,涉及密碼簽名檢查。為了進行調試,您可以使用Google的tokeninfo端點與服務器或設備上實現的本地處理進行比較。假設您的ID令牌的值為XYZ123 。然後,您將取消引用URI https://oauth2.googleapis.com/tokeninfo?id_token= XYZ123 。如果令牌簽名有效,則響應將是其解碼的JSON對象形式的JWT有效負載。

tokeninfo端點對於調試很有用,但出於生產目的,請從密鑰端點檢索Google的公共密鑰並在本地執行驗證。您應該使用jwks_uri元數據值從“發現”文檔中檢索密鑰URI。對調試端點的請求可能受到限制,否則可能會出現間歇性錯誤。

由於Google很少更改其公共密鑰,因此您可以使用HTTP響應的cache指令對它們進行高速緩存,並且在大多數情況下,比使用tokeninfo端點更有效地執行本地驗證。此驗證需要檢索和解析證書,並進行適當的加密調用以檢查簽名。幸運的是,可以使用多種語言調試良好的庫來完成此任務(請參見jwt.io )。

獲取用戶資料信息

要獲取有關用戶的其他配置文件信息,您可以使用訪問令牌(您的應用程序在身份驗證流程中接收到的訪問令牌)和OpenID Connect標準:

  1. 為了符合OpenID,您必須在身份驗證請求中包括openid profile範圍值。

    如果要包括用戶的電子郵件地址,可以指定其他範圍的email值。要同時指定profileemail ,可以在身份驗證請求URI中包括以下參數:

    scope=openid%20profile%20email
  2. 將訪問令牌添加到授權標頭中,並向userinfo端點發出HTTPS GET請求,您應該使用userinfo_endpoint元數據值從“發現”文檔中檢索該請求。 userinfo響應包括有關用戶的信息,如OpenID Connect Standard Claims所述,以及Discovery文檔中claims_supported元數據值中所述。用戶或其組織可能選擇提供或保留某些字段,因此您可能無法獲得授權訪問範圍的每個字段的信息。

發現文件

OpenID Connect協議要求使用多個端點來認證用戶,並請求包括令牌,用戶信息和公共密鑰的資源。

為了簡化實現並提高靈活性,OpenID Connect允許使用“發現文檔”,這是在知名位置找到的JSON文檔,其中包含鍵值對,這些鍵值對提供有關OpenID Connect提供程序配置的詳細信息,包括授權的URI。 ,令牌,吊銷,用戶信息和公共密鑰端點。 Google的OpenID Connect服務的“發現”文檔可以從以下位置檢索:

https://accounts.google.com/.well-known/openid-configuration

要使用Google的OpenID Connect服務,您應該將發現文檔URI( https://accounts.google.com/.well-known/openid-configuration )硬編碼到您的應用程序中。您的應用程序將獲取文檔,在響應中應用緩存規則,然後根據需要從文檔中檢索端點URI。例如,要對用戶進行身份驗證,您的代碼將檢索authorization_endpoint元數據值(在下面的示例中為https://accounts.google.com/o/oauth2/v2/auth ),作為發送到的身份驗證請求的基本URI。谷歌。

這是此類文檔的示例;字段名稱是在OpenID Connect Discovery 1.0中指定的名稱(有關其含義,請參閱該文檔)。這些值純粹是說明性的,並且可能會更改,儘管它們是從實際Google Discovery文檔的最新版本中復製而來的:

{
  "issuer": "https://accounts.google.com",
  "authorization_endpoint": "https://accounts.google.com/o/oauth2/v2/auth",
  "device_authorization_endpoint": "https://oauth2.googleapis.com/device/code",
  "token_endpoint": "https://oauth2.googleapis.com/token",
  "userinfo_endpoint": "https://openidconnect.googleapis.com/v1/userinfo",
  "revocation_endpoint": "https://oauth2.googleapis.com/revoke",
  "jwks_uri": "https://www.googleapis.com/oauth2/v3/certs",
  "response_types_supported": [
    "code",
    "token",
    "id_token",
    "code token",
    "code id_token",
    "token id_token",
    "code token id_token",
    "none"
  ],
  "subject_types_supported": [
    "public"
  ],
  "id_token_signing_alg_values_supported": [
    "RS256"
  ],
  "scopes_supported": [
    "openid",
    "email",
    "profile"
  ],
  "token_endpoint_auth_methods_supported": [
    "client_secret_post",
    "client_secret_basic"
  ],
  "claims_supported": [
    "aud",
    "email",
    "email_verified",
    "exp",
    "family_name",
    "given_name",
    "iat",
    "iss",
    "locale",
    "name",
    "picture",
    "sub"
  ],
  "code_challenge_methods_supported": [
    "plain",
    "S256"
  ]
}

您可以通過緩存“發現”文檔中的值來避免HTTP往返。使用標準的HTTP緩存標頭,應予以遵守。

客戶端庫

以下客戶端庫通過與流行的框架集成,使OAuth 2.0的實現更加簡單:

符合OpenID Connect

Google的OAuth 2.0身份驗證系統支持OpenID Connect Core規範的 必需功能。任何旨在與OpenID Connect一起使用的客戶端都應與此服務進行互操作( OpenID請求對象除外)。