2011-11-29 60 views
51

我使用Facebook登錄來識別用戶。當新用戶來到時,我將他們的用戶ID存儲在我的數據庫中。他們下次來時,我認出了他們的Facebook ID,並且知道它在我的數據庫中是哪個用戶。如何識別Google OAuth2用戶?

現在我正在嘗試使用Google的OAuth2做同樣的事情,但是如何識別用戶呢?

Google向我發送了幾個代碼和令牌(access_token,id_token,refresh_token),但是它們都不是常量。意思是如果我在2分鐘後註銷並重新登錄,則所有3個值都已更改。我怎樣才能唯一識別用戶?

我使用他們的PHP客戶端庫: 「這是誰」 https://code.google.com/p/google-api-php-client/

回答

26

我插入這個方法到谷歌-API的PHP的客戶端/ SRC/apiClient.php:

public function getUserInfo() 
{ 
    $req = new apiHttpRequest('https://www.googleapis.com/oauth2/v1/userinfo'); 
    // XXX error handling missing, this is just a rough draft 
    $req = $this->auth->sign($req); 
    $resp = $this->io->makeRequest($req)->getResponseBody(); 
    return json_decode($resp, 1); 
} 

現在我可以調用:

$client->setAccessToken($_SESSION[ 'token' ]); 
$userinfo = $client->getUserInfo(); 

它返回一個這樣的數組(加如果範圍已要求電子郵件):

Array 
(
    [id] => 1045636599999999999 
    [name] => Tim Strehle 
    [given_name] => Tim 
    [family_name] => Strehle 
    [locale] => de 
) 

該解決方案源於此線程:https://groups.google.com/forum/#!msg/google-api-php-client/o1BRsQ9NvUQ/xa532MxegFIJ

+4

請注意,Google最近更改了響應,現在'id_token'包含的是靜態標識符,而不是'id'中的密鑰'sub',如上例所示。 AFAIK,這個改變是他們對OpenID Connect協議的解釋。不幸的是,當我寫這篇文章時,回覆看起來有些隨意:有時它是'id',有時它是'sub',所以我需要支持這兩者。 –

1

本質上是一種服務;您必須請求訪問它作爲範圍,然後請求Google配置文件資源服務器以獲取身份。詳情請參閱OAuth 2.0 for Login

+0

這似乎是最技術上是正確的,但它缺乏額外的細節,目前公認的答案了。把兩個答案合併在一起,你就有了黃金。 –

76

正如其他人所說,你可以一個GET發送到https://www.googleapis.com/oauth2/v3/userinfo,使用的OAuth2承載令牌您剛剛收到,你將獲得有關用戶的一些信息的響應( ID,名稱等)。

另外值得一提的是,Google實施了OpenID Connect,並且此用戶信息端點只是其中的一部分。

OpenID Connect是位於OAuth2之上的驗證層。在Google令牌端點交換授權code時,您將獲得訪問令牌(access_token參數)以及OpenID Connect ID令牌(參數id_token)。

這兩個令牌都是JWT(JSON Web令牌,http://tools.ietf.org/html/draft-ietf-oauth-json-web-token)。

如果你解碼它們,你會得到一些斷言,包括用戶的id。如果您將此ID鏈接到數據庫中的用戶,您可以立即識別它們而無需執行額外的userinfo GET(節省時間)。

正如評論中所述,這些令牌使用Google的私鑰簽名,您可能需要使用Google公鑰(https://www.googleapis.com/oauth2/v3/certs)驗證簽名以確保它們是真實的。

您可以通過粘貼https://jwt.io/(向下滾動以查看JWT調試器)來查看JWT中的內容。斷言看起來像:

{ 
    "iss":"accounts.google.com", 
    "id":"1625346125341653", 
    "cid":"8932346534566-hoaf42fgdfgie1lm5nnl5675g7f167ovk8.apps.googleusercontent.com", 
    "aud":"8932346534566-hoaf42fgdfgie1lm5nnl5675g7f167ovk8.apps.googleusercontent.com", 
    "token_hash":"WQfLjdG1mDJHgJutmkjhKDCdA", 
    "iat":1567923785, 
    "exp":1350926995 
} 

還有一些庫用於各種編程語言以編程方式解碼JWTs。

PS:要獲得Google OpenID Connect提供商支持的URL和功能的最新列表,您可以檢查該URL:https://accounts.google.com/.well-known/openid-configuration

+1

是的,但爲了安全地使用這些信息,您必須驗證JWT的顯着性,爲此你需要公鑰。任何想法谷歌使他們的公共密鑰可用? – jazmit

+7

好的,找到它了:https://www.googleapis.com/oauth2/v1/certs 我還應該指出,進行驗證是絕對必要的,否則攻擊者可以使用任何已經註冊的應用程序輕鬆登錄到您的應用程序谷歌帳戶。 – jazmit

+0

@jamesinchina如果信息本身直接來自Google,而不是來自攻擊者,您認爲這種攻擊是可能的嗎? – stroncium

1

Altough JWTs可以在本地使用公鑰驗證,(谷歌API客戶端庫下載並緩存它們的公共密鑰自動)通過https://www.googleapis.com/oauth2/v1/tokeninfo端點檢查對谷歌的側令牌是必要的,以檢查是否爲一個應用的訪問已自創建令牌後被撤銷。

9

應該提到的是,OpenID Connect API不再返回id屬性。

現在是sub屬性,它作爲唯一的用戶標識。

Google Dev OpenID Connect UserInfo

+1

)維護。不確定這是否正確。儘管文檔狀態如何,如果我重新啓動我的auth服務器,清除緩存並重新登錄,'sub'是不同的。 – HockeyJ

+0

還有其他人有與'子'更改爲相同的登錄HockeyJ的問題? – dardawk