zoukankan      html  css  js  c++  java
  • 程序员的长安十二时辰:Java实现从Google oauth2.0认证调用谷歌内部api

    最近公司在做一个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".

     
  • 相关阅读:
    湘潭oj1203/邀请赛A称号 数论+java睑板
    Ejb in action(七)——message与JMS
    Post和Get差异
    1.cocos2dx它Menu(CCMenuItemFont,CCMenuItemImage,CCMenuItemLabel,CCMenuItemSprite,CCMenuItemToggle)
    ftk学习记录(IME文章)
    内部类创建一个内部版本
    使用gson和httpclient呼叫微信公众平台API
    hdu
    Beginning Python From Novice to Professional (5) - 条件与循环
    24点经典算法
  • 原文地址:https://www.cnblogs.com/noahpk/p/11254222.html
Copyright © 2011-2022 走看看