使用 Google Play Developer API 进行服务器端授权?

Posted

技术标签:

【中文标题】使用 Google Play Developer API 进行服务器端授权?【英文标题】:Server side authorization with Google Play Developer API? 【发布时间】:2018-06-18 23:02:42 【问题描述】:

从Google Play Developer API获取信息需要授权。

我知道如何使用 Postman 执行此操作,但实现授权要麻烦得多(重定向 url、处理重定向等等...) 这些将是您已经在 Google Developer API Console 中设置身份验证数据时的步骤。

1.) GET https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/androidpublisher&response_type=code&access_type=offline&redirect_uri=http://www.myurl.com/oauth2callback&client_id=1234567890.apps.googleusercontent.com
2.) get code which was sent to redirect url. 
3.) POST https://accounts.google.com/o/oauth2/token
with
    grant_type:authorization_code
    code:[the code I got before]
    client_id:1234567890.apps.googleusercontent.com
    client_secret:[my client secret]
4.) Invoke GET https://www.googleapis.com/androidpublisher/v2/applications/packageName/purchases/subscriptions/subscriptionId/tokens/token
with:
  Scope: https://www.googleapis.com/auth/androidpublisher
and:
  access_token as query parameter I got before.

现在我想以编程方式完成所有这些工作。显然不是那么容易。我认为Google API Client Libraries 会有所帮助,但我不明白这些库如何帮助我解决我的用例。 例如 GoogleAuthorizationCodeFlow 之类的类在请求时需要一个用户 ID,但我现在不一定有一个,所以我想知道应该如何以干净的方式使用这个 API。

是否有一种简洁的方法可以使用一些 API 更轻松地/以编程方式处理 OAuth2.0 以访问 Google Play Developer API?否则我必须手动实现。

【问题讨论】:

这是一个非常广泛的问题。 @jpaugh 不,不是。我确信解决方案是一些 API 类的组合。任何我想我不是唯一一个有这个问题的人。 对库推荐或示例代码的请求都被视为离题。询问如何使用 API 可以成为话题。 【参考方案1】:

在经历了很多头痛之后(就像总是使用 Google API 和服务一样),我想出了如何使用现有 API 访问 Google Play Developer API 信息(例如计费)。

1.) 在开发人员 API 控制台中创建服务帐户 (JSON) 密钥:

2.) 下载此 service-account-private-key.json 文件(不要将其与 OAuth2.0 客户端机密文件混淆!)。

3.) 在 Google Play 开发者控制台中转到 Settings -> Users & Permissions -> Invite New User 并将下载文件中的 client_email 设置为新用户的用户电子邮件。通过此视图中的复选框(例如“查看财务数据”)分配您要授予此用户的访问权限。

4.) 为您的项目添加适当的依赖项(版本 ...-1.23.0 对我不起作用):

<dependency>
    <groupId>com.google.apis</groupId>
    <artifactId>google-api-services-androidpublisher</artifactId>
    <version>v2-rev50-1.22.0</version>
</dependency>

5.) 将 service-account-private-key.json 文件加载到您的应用程序中。就我而言,它是一个网络服务器:

@Singleton
@Startup
public class WebserverConfiguration

    private String serviceAccountPrivateKeyFilePath;

    /** Global instance of the HTTP transport. */
    public static HttpTransport HTTP_TRANSPORT;

    /** Global instance of the JSON factory. */
    public static JsonFactory JSON_FACTORY;

    private GoogleCredential credential;

    @PostConstruct
    public void init()
    
        assignServiceAccountFileProperty();
        initGoogleCredentials();
    

    public String getServiceAccountPrivateKeyFilePath()
    
        return serviceAccountPrivateKeyFilePath;
    

    public GoogleCredential getCredential()
    
        return credential;
    

    private void initGoogleCredentials()
    
        try
        
            newTrustedTransport();
            newJsonFactory();

            String serviceAccountContent = new String(Files.readAllBytes(Paths.get(getServiceAccountPrivateKeyFilePath())));
            InputStream inputStream = new ByteArrayInputStream(serviceAccountContent.getBytes());

            credential = GoogleCredential.fromStream(inputStream).createScoped(Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER));

        
        catch (IOException | GeneralSecurityException e)
        
            throw new InitializationException(e);
        
    

    private void newJsonFactory()
    
        JSON_FACTORY = JacksonFactory.getDefaultInstance();
    

    private void assignServiceAccountFileProperty()
    
        serviceAccountPrivateKeyFilePath = System.getProperty("service.account.file.path");
        if (serviceAccountPrivateKeyFilePath == null)
        
            throw new IllegalArgumentException("service.account.file.path UNKNOWN - configure it as VM startup parameter in Wildfly");
        
    

    private static void newTrustedTransport() throws GeneralSecurityException, IOException
    
        if (HTTP_TRANSPORT == null)
        
            HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
        
    

6.) 现在我可以获取 Google Play Developer API 信息,例如评论:

private void invokeGoogleApi() throws IOException
       
    AndroidPublisher publisher = new AndroidPublisher.Builder(WebserverConfiguration.HTTP_TRANSPORT, WebserverConfiguration.JSON_FACTORY, configuration.getCredential()).setApplicationName("The name of my app on Google Play").build();
    AndroidPublisher.Reviews reviews = publisher.reviews();
    ReviewsListResponse reviewsListResponse = reviews.list("the.packagename.of.my.app").execute();
    logger.info("review list response = " + reviewsListResponse.toPrettyString());

这行得通。

我还不能测试它,但我确信获取帐单信息也可以:

private SubscriptionPurchase getPurchase() throws IOException

    AndroidPublisher publisher = new AndroidPublisher.Builder(WebserverConfiguration.HTTP_TRANSPORT, WebserverConfiguration.JSON_FACTORY, configuration.getCredential()).setApplicationName("The name of my app on Google Play").build();
    AndroidPublisher.Purchases purchases = publisher.purchases();

    SubscriptionPurchase purchase = purchases.subscriptions().get("the.packagename.of.my.app", "subscriptionId", "billing token sent by the app").execute();

    //do something or return
    return purchase;

【讨论】:

我们是否应该在将 json 文件的内容存储在某个位置时对其进行加密,否则我发现任何可以访问它的人都可以轻松读取它。我在想内容应该存储在一个加密文件中,当我们阅读时,我们应该解密它然后提供它。 @africandrogba 不一定。服务器将从一个特殊用户开始,该用户是唯一对该文件具有读取权限的用户。 (权限 rwx --- ---)。只有这个用户和 root 可以读取这个文件,如果有人获得 root 访问权限,那么无论如何都会丢失。 AndroidPublisher 发布者 = new AndroidPublisher.Builder(WebserverConfiguration.HTTP_TRANSPORT, WebserverConfiguration.JSON_FACTORY, WebserverConfiguration.getCredential()).setApplicationName(String.valueOf(R.string.app_name)).build();在此行中获取空点异常@Bevor @MuntasirAonik 你甚至没有说什么是空的,所以我回答这个问题的信息太少了。【参考方案2】:

在 Java here 中有完整的代码示例和文档

在Java source code这个授权是这样的

private static Credential authorizeWithServiceAccount(String serviceAccountEmail)
            throws GeneralSecurityException, IOException 
        log.info(String.format("Authorizing using Service Account: %s", serviceAccountEmail));

        // Build service account credential.
        GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(HTTP_TRANSPORT)
                .setJsonFactory(JSON_FACTORY)
                .setServiceAccountId(serviceAccountEmail)
                .setServiceAccountScopes(
                        Collections.singleton(AndroidPublisherScopes.ANDROIDPUBLISHER))
                .setServiceAccountPrivateKeyFromP12File(new File(SRC_RESOURCES_KEY_P12))
                .build();
        return credential;
    

【讨论】:

我无法使用“clientId”实例化 GoogleAuthorizationCodeFlow,但在https://developers.google.com/api-client-library/java/google-api-java-client/oauth2 的下一步中,他们会说'This flow is implemented using GoogleAuthorizationCodeFlow. The steps are: End-user logs in to your application. You will need to associate that user with a user ID that is unique for your application. - 这个“用户 ID”让我感到困惑。首先,我认为这是 GoogleID(当用户使用 Google 登录时获得)但也许我错了,这是我可以分配的一些随机代码。会试试的。 添加了官方示例的链接,希望它们比我之前的答案解释得更好。 这似乎很有帮助。我将尝试通过这些示例找到解决方案。

以上是关于使用 Google Play Developer API 进行服务器端授权?的主要内容,如果未能解决你的问题,请参考以下文章

使用 Google Play Developer API 取消发布应用

Google Play Developer API - 超出配额

获取访问令牌Google Play Android Developer API

获取访问令牌 Google Play Android Developer API

使用 Google Play Developer API 进行服务器端授权?

使用 Google Play Android Developer API 一段时间后“超出每日保存配额”