最近公司在做一個app購買的功能,主要思路就是客戶在app上購買套餐以後,Google自動推送訊息到Java後端,然後Java後端通過訂單的token獲取訂單資訊,儲存到資料庫。
Java後端要獲取訂單資訊,除了一個訂單token還不夠,還需要通過goole的oauth驗證拿到一個accessToken才行,但是怎麼才能獲取到accessToken呢,
在這個過程中,我採坑無數,終於在偉大的同性交友網站GitHub上面找到了答案。
首先,網上的教程一般都是這樣的:
一. 在Google Developer Console中建立一個Oauth客戶端ID,選擇Web Application賬戶,得到client_id,client_secret 和 redirect_uri,這3個引數後邊步驟常用到(此為前提)
二. 使用上一步獲取到的引數獲取Authorization code
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_token
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_token
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".