Google云端硬盘/ OAuth - 无法弄清楚如何获得可重复使用的GoogleCredentials

时间:2012-09-18 14:54:32

标签: google-drive-api credentials

我已成功安装并运行Google Drive Quick Start application called DriveCommandLine。我还为我的云端硬盘帐户中的一个文件获取了一些GET文件信息。

我现在要做的是以某种方式保存凭据并重新使用它们,而无需用户每次都必须访问网页才能获得授权代码。我已检查this page,其中包含检索和使用OAuth 2.0凭据的说明。为了使用示例类(MyClass),我修改了DriveCommandLine中实例化Credential对象的行:

Credential credential = MyClass.getCredentials(code, "");

这会导致抛出以下异常:

java.lang.NullPointerException
    at com.google.common.base.Preconditions.checkNotNull(Preconditions.java:187)
    at com.google.api.client.json.jackson.JacksonFactory.createJsonParser(JacksonFactory.java:84)
    at com.google.api.client.json.JsonFactory.fromInputStream(JsonFactory.java:247)
    at com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets.load(GoogleClientSecrets.java:168)
    at googledrive.MyClass.getFlow(MyClass.java:145)
    at googledrive.MyClass.exchangeCode(MyClass.java:166)
    at googledrive.MyClass.getCredentials(MyClass.java:239)
    at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
    at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)

我一直在关注这些API(Google云端硬盘和OAuth)2天,但进展甚微。我非常感谢上述错误以及获得持久凭据的问题。

这整个结构对我来说似乎不必要地复杂化。有人想解释为什么我不能通过传入我的Google用户名和密码来创建一个简单的凭据对象吗?

谢谢, Brian O Carroll,都柏林,爱尔兰

*更新*

好的,我刚刚解决了上述错误,现在又换了一个新错误。

我解决第一个问题的方法是修改MyClass.getFlow()。我没有使用json文件创建GoogleClientServices对象,而是使用了不同版本的GoogleAuthorizationCodeFlow.Builder,它允许您直接输入客户端ID和客户端密码作为字符串:

flow = new GoogleAuthorizationCodeFlow.Builder(httpTransport, jsonFactory, "<MY CLIENT ID>", "<MY CLIENT SECRET>", SCOPES).setAccessType("offline").setApprovalPrompt("force").build();

我现在遇到的问题是,当我尝试使用flow(GoogleAuthorizationCodeFlow对象)来交换Credentials对象的授权代码时,我收到以下错误:

An error occurred: com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
  "error" : "invalid_scope"
}
googledrive.MyClass$CodeExchangeException
        at googledrive.MyClass.exchangeCode(MyClass.java:185)
        at googledrive.MyClass.getCredentials(MyClass.java:262)
        at googledrive.DriveCommandLine.<init>(DriveCommandLine.java:56)
        at googledrive.DriveCommandLine.main(DriveCommandLine.java:115)

我应该使用其他一些范围吗?我目前正在使用MyClass提供的范围数组:

private static final List<String> SCOPES = Arrays.asList(
        "https://www.googleapis.com/auth/drive.file",
        "https://www.googleapis.com/auth/userinfo.email",
        "https://www.googleapis.com/auth/userinfo.profile");

谢谢!

3 个答案:

答案 0 :(得分:13)

我感觉到你的痛苦。我已经两个月了,仍然感到惊讶。

我的一些学习......

  • 请求用户权限时,请指定“offline = true”。这将(“有时”sic)返回一个refreshtoken,这与具有受限权限的密码一样好。您可以存储它并在任何时候重复使用它(直到用户撤销它)以获取访问令牌。

  • 我的感觉是Google SDK更像是一种阻碍,而不是一种帮助。我一个接一个地停止使用它们,现在直接调用REST API。

  • 关于您的最后一点,您可以(仅)使用Google客户端登录协议访问上一代API。然而,这完全被弃用,很快就会被关闭。 OAuth旨在对授权进行细粒度控制,这本质上是复杂的。因此,尽管我同意它很复杂,但我认为这并不是必然的。我们生活在一个复杂的世界: - )

您和我的经验表明,开发社区仍然需要一个合并的文档和配方,以便将这些内容放入我们的后视镜中,这样我们就可以专注于手头的任务。

答案 1 :(得分:3)

Oath2Scopes导入如下:

import com.google.api.services.oauth2.Oauth2Scopes;

您需要在类路径中使用jar文件“google-api-services-oauth2-v2-rev15-1.8.0-beta.jar”来访问该程序包。可以下载here

不,我不知道如何在不必访问授权URL至少一次的情况下获取凭据并复制代码。我修改了MyClass来存储和检索数据库中的凭据(在我的例子中,它是一个包含userid,accesstoken和refreshtoken的简单表)。这样我只需要获取授权代码一次,一旦获得访问/刷新令牌,我就可以重复使用它们来创建GoogleCredential对象。以下是Imake GoogleCredential对象:

GoogleCredential credential = new GoogleCredential.Builder().setJsonFactory(jsonFactory)
            .setTransport(httpTransport).setClientSecrets(clientid, clientsecret).build();
    credential.setAccessToken(accessToken);
    credential.setRefreshToken(refreshToken);

只需输入上面的clientid,clientsecret,accessToken和refreshToken。

我真的没有太多的时间来分离和整理我的整个代码以便在这里发布,但如果你仍然遇到问题,请告诉我,我会看到我能做些什么。虽然,你实际上是在向盲人询问方向。我对整个系统的理解非常粗略!

干杯, 布赖恩

答案 2 :(得分:1)

好的,我终于解决了上面的第二个问题,我终于得到了一个带有访问令牌和刷新令牌的GoogleCredential对象。

我一直在尝试通过修改 MyClass (管理凭据的范围)中的范围列表来解决范围问题。最后,我需要调整修改后的 DriveCommandLine 版本(最初用于获取授权码的版本)的范围。我在Oauth2Scopes中添加了两个范围:

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(
    httpTransport, jsonFactory, CLIENT_ID, CLIENT_SECRET,
    Arrays.asList(DriveScopes.DRIVE, Oauth2Scopes.USERINFO_EMAIL, Oauth2Scopes.USERINFO_PROFILE))
    .setAccessType("offline").setApprovalPrompt("force").build();

添加用户信息的范围允许我稍后在MyClass中获取用户ID。我现在可以使用userid将凭据存储在数据库中以供重用(无需每次都让用户转到URL)。我还按照pinoyyid的建议将访问类型设置为“离线”。