2014-06-18 58 views
0

我有一個基於瀏覽器的應用程序(單頁,AngularJS),並使用hello使用第三方登錄,如Google,FB,Soundcloud等。如何使用OAuth2基於瀏覽器的身份驗證,然後驗證服務器上的記錄

我的應用程序使用PHP API服務器。

讓用戶能夠使用Google登錄,並驗證服務器端用戶的好方法是什麼?

我正在考慮:

  • 的瀏覽器應用程序進行與谷歌/ FB /等
  • 我然後從客戶端傳送的access_token到服務器,然後使用,例如,一個谷歌的一個隱式許可-api-php-client與我的app id,祕密和用戶access_token?使用他們的API,如/me? (這是哪種授予類型?)
  • 從第三方(facebook_id,電子郵件等)檢索一些密鑰,將其與我的數據庫中的用戶相匹配,然後考慮用戶認證?

此外,我應該對每個API請求執行此操作嗎?或者我應該只是將access_token藏起來,並假定用戶在密鑰過期之前仍然有效?

回答

1

一個問題是,並非所有這些提供程序都支持隱式流。但假設他們這樣做,你得到的每個access_token都會證明用戶使用該系統進行了身份驗證,而不一定他們有權訪問您的 API。您仍然需要一些信息,聲稱「[email protected]可以」讀取「您系統中的資源X」

您可能需要將Google,Soundcloud等獲得的任何內容轉換爲應用程序理解的令牌。一個簡單的(r)格式是使用JWT。 (Json Web Tokens)。

App -> Intermmediary -> Soundcloud/Google <-JWT--+ <---whavetever-+

然後:

App - (JWT) -> API

JWT是容易操縱,驗證和核實。見jwt.io

,你可能覺得this blog post看起來也爲博客文章@歐亨尼奧-步伐提到的是用於設置客戶端真正有用的一些附加信息(特別是在AngularJS前端)

+0

因此,如果我明白了,我可以將足夠的內容放入JWT中,以證明用戶已通過身份驗證?即它將包含一個帶有令牌的電子郵件,該令牌只能由服務X創建;並提供JWT是合法的,系統會知道它包含真正的信息?那麼我的系統就不需要獨立地調用Google/FB/etc了? (現在閱讀博客文章) – Matt

+0

是的。 JWT是一個自包含的實體,包含關於用戶的信息:(例如姓名,電子郵件)或與您的API有關的用戶(例如,用戶是「管理員」)。它是數字簽名的,所以你可以檢查完整性。你可以在後臺檢查簽名而不需要額外的服務器請求,它只是一個加密函數。 –

+0

我仍然不明白這可能是絕對安全的。我遵循你的博客文章中的建議(真的很有幫助!)我認爲讓這個安全的唯一方法是讓服務器使用它接收的access_token並根據服務(google/fb/...)進行查詢。最安全的方式我可以想象的是,使用一個鍵(例如電子郵件)作爲索賠中的「子」,並將用戶標識作爲祕密來形成智威湯遜(如您所建議的)。但即使這可能是假的。 – Matt

0

。對於服務器端,應該被驗證。

SDK的是(在作曲家)(代碼如下):

  • Facebook的:"facebook/php-sdk-v4" : "4.0.*"
  • 谷歌:cURL請求(不關心"google/apiclient"
  • 的SoundCloud:"ise/php-soundcloud": "3.*"

(當然還有其他的,這三個是我選擇的,看起來很體面。)

上次我做了這樣的事情,我犯了一個錯誤,在每個請求上驗證access_token,這對性能有巨大的(顯然是負面的)影響。現在我只是在登錄時驗證它並使用它從該服務中檢索用戶的ID。所以,瀏覽器發給我access_token A,並說它來自Facebook,我使用Facebook上面的access_token上面的sdk,並且我取回他們的ID,所以我知道他們是誰,他們是誰。

我建議在expires_in服務器上存儲access_token

我沒有處理刷新令牌的又

代碼使用上述庫來驗證令牌:

function validateTokenFacebook($token, $id=null) { 
    // Performed above 
    // FacebookSession::setDefaultApplication($config->fb->app_id, $config->fb->secret); 

    $session = new FacebookSession($token); 

    // Fetch user info 
    $request = new FacebookRequest($session, 'GET', '/me'); 
    try { 
     $response = $request->execute(); 
    } catch (\Facebook\FacebookServerException $e) { 
     $this->mlog->err($e . "\n" . $e->getTraceAsString()); 
     throw new AuthTokenInvalidException(); 
    } 

    $graphObject = $response->getGraphObject(); 

    $user_id = $graphObject->getProperty('id'); 
    return array(access_token, $user_id); 
} 
function validateTokenGoogle($token, $id=null) { 
    $resp=array(); 

    // This key isn't included in the token from hello.js, but 
    // google needs it 
    if (!array_key_exists('created', $token)) $token['created'] = $token['expires'] - $token['expires_in']; 

    $client = new \Google_Client(); 
    $client->setClientId($this->systemConfig->google->app_id); 
    $client->setClientSecret($this->systemConfig->google->secret); 
    $client->setRedirectUri($this->systemConfig->google->redirectUri); 
    $client->setScopes('email'); 
    $client->setAccessToken(json_encode($token)); 

    try { 
     // Send Client Request 
     $objOAuthService = new \Google_Service_Oauth2($client); 
     $userData = $objOAuthService->userinfo->get(); 
     return array($token['access_token'], $userData['id']); 
    } catch (\Google_Auth_Exception $e) { 
     throw new AuthException('Google returned ' . get_class($e)); 
    } 
} 
function validateTokenSoundcloud($token, $id=null) { 
    $soundcloud = new \Soundcloud\Service(
     $this->systemConfig->soundcloud->app_id, 
     $this->systemConfig->soundcloud->secret, 
     $this->systemConfig->soundcloud->redirect); 
    $soundcloud->setAccessToken($access_token); 
    try { 
     $response = json_decode($soundcloud->get('me'), true); 
     if (array_key_exists('id', $response)) 
      return array($access_token, $response['id']); 
    } catch (Soundcloud\Exception\InvalidHttpResponseCodeException $e) { 
     $this->mlog->err($e->getMessage()); 
    } 
    throw new AuthTokenInvalidException(); 
} 

我有以上幾個自定義類,如異常和systemConfig,但我認爲它足夠詳細以傳達他們所做的事情。

相關問題