9

我無法從Google獲取一次性授權碼。我試圖從Android客戶端獲取授權碼,以便將其發送到我的Rails後端(Web客戶端)。獲取Google一次性授權碼

在我的谷歌雲開發者控制檯我有兩個客戶端ID的應用程序:

  1. 客戶端ID用於Web應用程序(我的導軌後端)的Android應用程序

  2. 客戶端ID(我Android客戶端)。使用的SHA1是〜/ .android/debug.keystore

假設網絡應用客戶端ID是12345.apps.googleusercontent.com

假設Android客戶端ID是67890.apps.googleusercontent.com

這是我的一些代碼:

private final static String WEB_CLIENT_ID = "12345.apps.googleusercontent.com"; 
private final static String GOOGLE_CALENDAR_API_SCOPE = "audience:server:client_id:" + WEB_CLIENT_ID; 

private void getAndUseAuthToken(final String email) { 
     AsyncTask task = new AsyncTask<String, Void, String>() { 
      @Override 
      protected String doInBackground(String... emails) { 
       try { 
        return GoogleAuthUtil.getToken(AddExternalCalendarsActivity.this, emails[0], GOOGLE_CALENDAR_API_SCOPE); 
       } catch (UserRecoverableAuthException e) { 
        startActivityForResult(e.getIntent(), IntentConstants.REQUEST_GOOGLE_AUTHORIZATION); 
       } catch (IOException e) { 
        e.printStackTrace(); 
       } catch (GoogleAuthException e) { 
        e.printStackTrace(); 
       } catch (Exception e) { 
        e.printStackTrace(); 
       } 

       return null; 
      } 

      @Override 
      protected void onPostExecute(String authToken) { 
       if (authToken != null) { 
        saveTokenAndGetCalendars(email, authToken); 
       } 
      } 
     }; 

     String[] emails = new String[1]; 
     emails[0] = email; 
     task.execute(emails); 
    } 

一些附加說明

  • 我打了GoogleAuthException和接收「未知」的消息詳情

  • 我無法在谷歌雲端控制檯的這個項目的權限添加其他成員 - 添加時新成員彈出窗口出現「服務器錯誤。哎呦!我們不好。「我已經派人反饋給谷歌的兩倍

  • 我指的是這個documentation注意下面的引述。‘固定’的,他們說的是,我並不需要預先觀衆:服務器:?在我GOOGLE_CALENDAR_API_SCOPE可變CLIENT_ID我都試過與不和仍然得到同樣的GoogleAuthException

在這種情況下,Android應用程序可以調用 GoogleAuthUtil.getToken()方法。代表設備上的任何Google 帳戶, nd的範圍參數值爲 受衆羣體:server:client_id:9414861317621.apps.googleusercontent.com。 前綴受衆羣體:服務器:client_id:是固定的,其餘的 範圍字符串是Web組件的客戶端ID。

  • 如果我用這個範圍內,我可以從谷歌設備認證。不過,我讀過的文檔表明,我需要在範圍中使用服務器Web客戶端ID(與Android客戶端ID在同一個Google控制檯項目中),以便服務器代表誰授權其在Android客戶端上的用戶:

    private final static String GOOGLE_CALENDAR_API_SCOPE = "oauth2:https://www.googleapis.com/auth/calendar";

更新1

我最初回答說: 原因我的第一個問題 - 我打了GoogleAuthException和接收「未知」作爲消息詳細信息 - 是我在將雲端控制檯中的Android客戶端ID添加時犯的一個錯誤。 SHA1是正確的,但我沒有正確輸入包名。當我的android包實際上是com.company.android.app時,我使用com.company.app。 原始問題中的代碼正常工作。只要確保您在Google雲端控制檯項目中擁有所有必要的客戶端即可。

但是還存在另一個問題。當我送從GoogleAuthUtil.getToken() Rails的後端返回的一次性授權令牌,然後嘗試換取一個和的access_token refresh_token,我得到如下:

Signet::AuthorizationError: 
    Authorization failed. Server message: 
    { 
     "error" : "invalid_grant" 
    } 

google documentation和幾個SO帖子表明我需要設置access_type=offline。但我認爲這是當您要求一次性授權碼和從Web服務器離線訪問時。我試圖從Android客戶端請求一次性授權碼並將其發送到網絡服務器。

這可能與GoogleAuthUtil.getToken()

更新2

谷歌加登錄必須在範圍內,即使你只是想訪問日曆:

private final static String GOOGLE_CALENDAR_API_SCOPE = "oauth2:server:client_id:" + WEB_CLIENT_ID + ":api_scope:https://www.googleapis.com/auth/plus.login https://www.googleapis.com/auth/calendar"; 

SO post是有益的。另外,Google's Cross Client identity documentation的狀態如下:

[注:此政策正逐步推出。目前,當訪問令牌都參與其中,當被請求的範圍包括https://www.googleapis.com/auth/plus.login.]

我會在回答中總結,如果代幣兌換工作on Rails的後端它只適用。

+0

如何使用GoogleAuthUtil.getToken()獲得脫機授權碼(access_type = offline)?你設法做到了嗎? – grebulon

+0

@grebulon是的,在完成接受答案中的內容後,我可以使用GoogleAuthUtil.getToken()獲得一次性授權代碼。我將該一次性授權代碼發送到我們的後端服務器,後端服務器使用它獲取谷歌API令牌。 – mikeorr85

+0

我幾乎得到它的工作...在我的流程中,我一直在獲取UserRecoverableAuthException(NeedPermission)的離線權限。啓動收到的意圖並調用getToken,再次爲脫機權限啓動添加權限對話框,等等無限循環。 – grebulon

回答

3

兩件事情解決了這個對我來說:

  1. 確保Android和Web客戶端ID在同一Google雲端控制檯項目中正確設置。

  2. 使用正確的範圍。另外需要登錄,即使你只是訪問日曆API:

    //被交換授權碼的訪問和刷新令牌

    私人最終靜態字符串WEB_CLIENT_ID =「12345網絡服務器的ID .apps.googleusercontent.com「; 私人最終靜態字符串GOOGLE_CALENDAR_API_SCOPE =「oauth2:server:client_id:」+ WEB_CLIENT_ID +「:api_scope:https://www.googleapis.com/auth/plus.loginhttps://www.googleapis.com/auth/calendar」;

0

這裏是我做了什麼:

final String authToken = GoogleAuthUtil.getTokenWithNotification (this.context, account.name, "oauth2:" + AuthUtils.profileScope, new Bundle(), 
       Contract.authority, new Bundle()); 

但你平原爲gettoken應該工作一樣的前臺活動。

取這個令牌,以一種可以像HTTP頭(通過HTTPS)的方式將它發送到服務器。只要服務器範圍是用於獲取令牌的範圍的子集,就不會有問題。服務器使用服務器ID,Android客戶端使用Android客戶端ID。

您應該將範圍設置爲:

oauth2:https://www.googleapis.com/auth/calendar 

oauth2:https://www.googleapis.com/auth/calendar.readonly 

https://developers.google.com/google-apps/calendar/auth

編輯:好的,我明白你正在嘗試做的。範圍值是使用空格分隔的列表,所以你可能會需要附加觀衆:服務器:CLIENT_ID:你的範圍,如:

"oauth2:https://www.googleapis.com/auth/calendar audience:server:client_id:12345-your-web-component-client-id" 
+0

感謝您的回覆。上面的範圍返回一個GoogleAuthException - 「INVALID_SCOPE」。我認爲這是因爲Google只需要來自同一個項目的客戶的授權。我*認爲*他們在說[這裏](https://developers.google.com/accounts/docs/CrossClientAuth) – mikeorr85