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".

     
  • 相关阅读:
    安全编码1
    VPP tips
    VPP概述汇总
    C语言安全编码摘录
    TCP-proxy
    Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.4. Matplotlib: plotting
    Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.3. NumPy: creating and manipulating numerical data
    Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.2. The Python language
    Scipy Lecture Notes学习笔记(一)Getting started with Python for science 1.1. Python scientific computing ecosystem
    25马5跑道,求最快的五匹马的需要比赛的次数
  • 原文地址:https://www.cnblogs.com/noahpk/p/11254222.html
Copyright © 2011-2022 走看看