程序員的長安十二時辰:Java實現從Google oauth2.0認證調用谷歌內部api

最近公司在作一個app購買的功能,主要思路就是客戶在app上購買套餐之後,Google自動推送消息到Java後端,而後Java後端經過訂單的token獲取訂單信息,保存到數據庫。php

Java後端要獲取訂單信息,除了一個訂單token還不夠,還須要經過goole的oauth驗證拿到一個accessToken才行,可是怎麼才能獲取到accessToken呢,java

在這個過程當中,我採坑無數,終於在偉大的同性交友網站GitHub上面找到了答案。android

首先,網上的教程通常都是這樣的:程序員

  一. 在Google Developer Console中建立一個Oauth客戶端ID,選擇Web Application帳戶,獲得client_id,client_secret 和 redirect_uri,這3個參數後邊步驟經常使用到(此爲前提)數據庫

        二. 使用上一步獲取到的參數獲取Authorization code json

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher
&response_type=code
&access_type=offline
&redirect_uri={REDIRECT_URIS}
&client_id={CLIENT_ID}

        咱們須要將這個URL以瀏覽器的形式打開,這時會跳出提示你Sign in with your Google Account,而後在用有project受權的谷歌帳戶登陸,地址欄會出現咱們所需的code。例如:https://www.example.com/oauth2callback?code=4/CpVOd8CljO_gxTRE1M5jtwEFwf8gRD44vrmKNDi4GSS.kr-GHuseD-oZEnp6UADFXm0E0MD3FlAI後端

        三. 利用code 獲取access_token,refresh_tokenapi

https://accounts.google.com/o/oauth2/token?
code={CODE}
&client_id={CLIENT_ID}
&client_secret={CLIENT_SECRET}
&redirect_uri={REDIRECT}
&grant_type=authorization_code
 

        咱們這一步的目的是獲取refresh_token,只要有了這個長效token,access_token是隨時能夠獲取的,第一次發起請求獲得的JSON字符串以下所示,之後再請求將再也不出現refresh_token,要保存好。expires_in是指access_token的時效,爲3600秒。瀏覽器

{
    "access_token": "ya29.3gC2jw5vm77YPkylq0H5sPJeJJDHX93Kq8qZHRJaMlknwJ85595eMogL300XKDOEI7zIsdeFEPY6zg", 
    "token_type": "Bearer", 
    "expires_in": 3600, 
    "refresh_token": "1/FbQD448CdDPfDEDpCy4gj_m3WDr_M0U5WupquXL_o"
}

        四. 進一步可利用refresh_token獲取新的access_tokentomcat

https://accounts.google.com/o/oauth2/token?
grant_type=refresh_token
&client_id={CLIENT_ID}
&client_secret={CLIENT_SECRET}
&refresh_token={REFRESH_TOKEN}

        五. 使用access_token 調用Google API 達到最終目的(若是access_token過期,回到第四步)

  而後使用accessToken便可調用谷歌的API了,例如要查看訂單的購買信息

  https://www.googleapis.com/androidpublisher/v3/applications/{packageName}/purchases/subscriptions/{subscriptionName}/tokens/ {purchaseToken}?access_token={accessToken}

而後看起來是否是很簡單,很方便?

但是我要在Java後端實現這些操做,卻沒有想象中這麼簡單了,首先第一步,獲取Authorization code這塊就犯了難,後端發起一個請求卻是不難,但是用有project受權的谷歌帳戶登陸受權,這塊真的是想大喊一聲:臣妾作不到啊!

那還能怎麼辦?固然不能就此罷休,在這裏仍是感謝萬能的度娘,終於讓我發現了plan B:

建立一個服務帳戶,經過帳戶的祕鑰來獲取token,簡要步驟以下:

1.獲取服務帳戶 Service Account

2.建立訪問程序,加載Service Account文件,獲取token並訪問請求API

是否是很簡單?很nice?來來咱們上圖說話:

1.首先選中咱們創造的Oauth客戶端,而後點擊建立服務帳戶祕鑰

2.選擇app Engine,Json格式

3.ok了,而後咱們再使用以下的代碼加載服務帳戶,獲取accessToken

import java.io.FileInputStream;
import java.util.Arrays;
import java.util.List;

import com.google.api.client.googleapis.auth.oauth2.GoogleCredential;

public class GoogleOAuth2ServiceAccountSample {

    /** OAuth 2.0 scopes. 重要,規範訪問者的查看範圍*/
    private static final List<String> SCOPES = Arrays.asList(
            "https://www.googleapis.com/auth/androidpublisher");

    public static void main(String[] args) {
        try {
            // 根據Service Account文件構造認證明例 GoogleCredential
            GoogleCredential credential = GoogleCredential
                    .fromStream(new FileInputStream(
                            "Google_Wallet-94e38f1f23f7.json"))// 加載服務賬戶認證文件
                    .createScoped(SCOPES);

            // 刷新token
            credential.refreshToken();

            // 獲取token
            System.out.println(credential.getAccessToken());

        } catch (Exception e) {
            e.printStackTrace();
        }
    }
}

4.這樣咱們就能獲取到accessToken了嗎?是的,我拿到了心心念唸的accessToken,但是在我使用token獲取訂單詳情的時候,卻報錯了。

 "errors": [ { "domain": "androidpublisher", "reason": "permissionDenied", "message": "The current user has insufficient permissions to perform the requested operation." } ], "code": 401, "message": "The current user has insufficient permissions to perform the requested operation." } }

說實話到這一步,我已經有些氣餒了,谷歌的官方文檔看了N遍,也沒有頭緒,到底該怎麼辦呢?

沒辦法,只能繼續google查找資料,畢竟國外的資料可能多一些,直到我看到這一篇文章:

5.好吧 看到這塊我是如獲至寶,趕忙操做起來,打開https://play.google.com/apps/publish,邀請我註冊的服務帳戶的郵箱,並給予管理訂單和查看財務數據的權限,ok!

 

6.而後就ok了嗎?我興致勃勃的又試了一下請求獲取訂單詳情的api,oh no!又是該死的報錯,和上面的如出一轍:

 "errors": [ { "domain": "androidpublisher", "reason": "permissionDenied", "message": "The current user has insufficient permissions to perform the requested operation." } ], "code": 401, "message": "The current user has insufficient permissions to perform the requested operation." } }
7.我完全無奈了,短短的三天已通過去了,對於這麼簡單的小功能我卻拿不下,實在有點羞愧難當,難道就這樣放棄了嗎?不!我永不言敗!
而後就繼續常規操做,google用英文關鍵字查詢,雖然本人英文很渣,可是靠着強大的谷歌翻譯,仍是能看懂七八分,哈哈!功夫不負有心人,靠着我頑強的毅力
終於讓我看到了一個答案:


what?
谷歌,你是我哥,真的!還有這種操做,帳戶更改須要24小時才能生效,word媽!
好吧 ,既然故事到了這裏,我就只能等吧,不就是24小時麼,就當是我程序員的長安十二時辰了,我等!
一晚上無眠。
翌日,我熟悉的啓動IDEA,啓動tomcat,心要跳到了嗓子眼,這一刻時間彷彿凝固了,我發起請求,一串期待已久的json字符串出如今我眼前:
{
 "kind": "androidpublisher#subscriptionPurchase",
 "startTimeMillis": "1564021170426",
 "expiryTimeMillis": "1564023267679",
 "autoRenewing": false,
 "priceCurrencyCode": "HKD",
 "priceAmountMicros": "949000000",
 "countryCode": "HK",
 "developerPayload": "",
 "cancelReason": 1,
 "orderId": "GPA.3309-8698-7096-01554..5",
 "purchaseType": 0,
 "acknowledgementState": 1
}
真的是激動的心,顫抖的手,就問兄弟你有沒有!哈哈!我能夠仰天大笑出門去,我輩豈是蓬蒿人!
快哉!!!!
好了,這個問題就告一段落了,在這裏在標註一下這個過程常見的一些問題,若是有道友也遇到,但願能夠解憂!

問題1: projectNotLinked

{
    "error": {
        "errors": [
            {
                "domain": "androidpublisher",
                "reason": "projectNotLinked",
                "message": "The project id used to call the Google Play Developer API has not been linked in the Google Play Developer Console."
            }
        ],
        "code": 403,
        "message": "The project id used to call the Google Play Developer API has not been linked in the Google Play Developer Console."
    }
}

在這個頁設置關聯:https://play.google.com/apps/publish/

ps:注意登錄帳戶必須是app全部者

Google Play Developer Console

1.  "Google Play Developer Console" > "Settings" > subcategory "API access".

2.  Make a link to your "Linked Project".

3.  "Service Account" place maybe already showing ur "Service account" CLIENT ID which made "google developer console".

相關文章
相關標籤/搜索