最近公司在作一個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用英文關鍵字查詢,雖然本人英文很渣,可是靠着強大的谷歌翻譯,仍是能看懂七八分,哈哈!功夫不負有心人,靠着我頑強的毅力
終於讓我看到了一個答案:
![](http://static.javashuo.com/static/loading.gif)
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".