Google Admin Directory API,错误请求400 invalid_grant。 (使用服务帐户)

时间:2016-07-06 21:52:18

标签: oauth-2.0 google-api bad-request service-accounts client-library

因此,在显示我的代码之前,让我解释一下我为“正确”设置服务帐户环境所采取的步骤。

  1. 在Google开发者控制台中,创建了服务帐户。 (这是我生成的客户ID(长号码),服务帐号(xxxxx@xxxx.iam.gserviceaccount.com),以及我在P12下载的私钥。
  2. 在管理控制台中,将客户端ID放在适当的范围内。就我而言,我添加的范围是https://www.googleapis.com/auth/admin.directory.group.readonlyhttps://www.googleapis.com/auth/admin.directory.group.member.readonly
  3. 在我的代码中,正确设置私钥路径和其他环境。

    def getDirectoryService: Directory = {
      val httpTransport: HttpTransport = new NetHttpTransport()
      val jsonFactory: JacksonFactory = new JacksonFactory()
      val credential: GoogleCredential = new GoogleCredential.Builder()
        .setTransport(httpTransport)
        .setJsonFactory(jsonFactory)
        .setServiceAccountId("xxxxx@xxxx.iam.gserviceaccount.com")
        .setServiceAccountScopes(util.Arrays.asList(DirectoryScopes.ADMIN_DIRECTORY_GROUP_READONLY, DirectoryScopes.ADMIN_DIRECTORY_GROUP_MEMBER_READONLY))
        .setServiceAccountUser("admin@domain.com")
        .setServiceAccountPrivateKeyFromP12File(
          new java.io.File("/pathToKey/privatekey.p12"))
        .build()
      val service: Directory = new Directory.Builder(httpTransport, jsonFactory, null)
        .setHttpRequestInitializer(credential).build()
      service
    }
    
  4. 然后我尝试执行类似这样的事情:

    service.groups().list().execute()  
    
  5.     service.groups().list("domain.com").execute()
    

    此代码将导致

    com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
    {
      "error" : "invalid_grant"
    }
            at com.google.api.client.auth.oauth2.TokenResponseException.from(TokenResponseException.java:105)
            at com.google.api.client.auth.oauth2.TokenRequest.executeUnparsed(TokenRequest.java:287)
            at com.google.api.client.auth.oauth2.TokenRequest.execute(TokenRequest.java:307)
            at com.google.api.client.googleapis.auth.oauth2.GoogleCredential.executeRefreshToken(GoogleCredential.java:384)
            at com.google.api.client.auth.oauth2.Credential.refreshToken(Credential.java:489)
            at com.google.api.client.auth.oauth2.Credential.intercept(Credential.java:217)
            at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:868)
            at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:419)
            at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:352)
            at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:469)
            at com.company.project.GoogleServiceProvider.getGroups(GoogleServiceProvider.scala:81)
            at com.company.project.ProjectHandler.handle(ProjectHandler.scala:110)
            at com.company.common.web.DispatcherServlet.service(DispatcherServlet.scala:40)
            at javax.servlet.http.HttpServlet.service(HttpServlet.java:790)
            at org.eclipse.jetty.servlet.ServletHolder.handle(ServletHolder.java:845)
            at org.eclipse.jetty.servlet.ServletHandler.doHandle(ServletHandler.java:583)
            at org.eclipse.jetty.server.session.SessionHandler.doHandle(SessionHandler.java:224)
            at org.eclipse.jetty.server.handler.ContextHandler.doHandle(ContextHandler.java:1174)
            at org.eclipse.jetty.servlet.ServletHandler.doScope(ServletHandler.java:511)
            at org.eclipse.jetty.server.session.SessionHandler.doScope(SessionHandler.java:185)
            at org.eclipse.jetty.server.handler.ContextHandler.doScope(ContextHandler.java:1106)
            at org.eclipse.jetty.server.handler.ScopedHandler.handle(ScopedHandler.java:141)
            at org.eclipse.jetty.server.handler.HandlerWrapper.handle(HandlerWrapper.java:134)
            at org.eclipse.jetty.server.Server.handle(Server.java:524)
            at org.eclipse.jetty.server.HttpChannel.handle(HttpChannel.java:319)
            at org.eclipse.jetty.server.HttpConnection.onFillable(HttpConnection.java:253)
            at org.eclipse.jetty.io.AbstractConnection$ReadCallback.succeeded(AbstractConnection.java:273)
            at org.eclipse.jetty.io.FillInterest.fillable(FillInterest.java:95)
            at org.eclipse.jetty.io.SelectChannelEndPoint$2.run(SelectChannelEndPoint.java:93)
            at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.executeProduceConsume(ExecuteProduceConsume.java:303)
            at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.produceConsume(ExecuteProduceConsume.java:148)
            at org.eclipse.jetty.util.thread.strategy.ExecuteProduceConsume.run(ExecuteProduceConsume.java:136)
            at org.eclipse.jetty.util.thread.QueuedThreadPool.runJob(QueuedThreadPool.java:671)
            at org.eclipse.jetty.util.thread.QueuedThreadPool$2.run(QueuedThreadPool.java:589)
            at java.lang.Thread.run(Thread.java:745)
    

    我怎么可能做错了?过去两天我一直在寻找解决方案,并尝试了很多东西。我还不确定的解决方案之一是ntp同步(如何将服务器时间与ntp完全同步)。

    任何adivce都会非常有帮助,谢谢!

    更新:我还确保激活管理员目录SDK,并在开发人员的控制台上启用了域范围的委派。

    更新#2:我忘了提到,管理员帐户不是项目本身的所有者。所以基本上,我是一个域的成员,我创建了一个项目,所以我是项目和服务帐户的唯一所有者。(我不是管理员)。但是,如果管理员是项目的所有者并创建服务帐户,以使其正常工作???

1 个答案:

答案 0 :(得分:1)

好的,我的问题是在setServiceAccountUser我放了管理员组的电子邮件地址,而不是实际的用户帐户。显然,它不允许将组电子邮件(别名)地址放入setServiceAccountUser。 因此,在输入具有管理员权限的实际用户帐户后,它似乎正在运行。

我仍然想知道什么是最好的做法。如同,我应该为项目创建一个具有管理员权限的单独用户帐户吗?我绝对不想在我的代码中输入管理员帐户的电子邮件地址。