【问题标题】:Google Directory API returns Not Authorized when call users().list().execute()Google Directory API 在调用 users().list().execute() 时返回 Not Authorized
【发布时间】:2013-09-05 07:07:39
【问题描述】:

我需要从我的 google 域中读取用户(和组)列表。

所以我去了我的 Google API 控制台并启用了 Admin SDK 并创建了一个 服务帐户 来调用 Google API。我使用以下谷歌库

  • google-api-services-admin-directory_v1-rev11-1.16.0-rc.jar
  • google-api-client-1.16.0-rc.jar

我的代码是

     /*
     * Global instance of the JSON factory.
     */
    final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();
     /*
      Global instance of the HTTP transport.
     */
        HttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();

        Collection<String> scopeList = new ArrayList<>();
        scopeList.add(DirectoryScopes.ADMIN_DIRECTORY_USER);
        scopeList.add(DirectoryScopes.ADMIN_DIRECTORY_GROUP);
        scopeList.add(DirectoryScopes.ADMIN_DIRECTORY_GROUP_MEMBER);

        GoogleCredential credential = new GoogleCredential.Builder()
                .setTransport(httpTransport)
                .setJsonFactory(JSON_FACTORY)
                .setServiceAccountId("nnnnnn@developer.gserviceaccount.com")
                .setServiceAccountScopes(scopeList)
                .setServiceAccountPrivateKeyFromP12File(new File("/Path/To/KeyFile/nnnnn-privatekey.p12"))
//                .setServiceAccountUser("admin@mydomain.org")
                .build();

        Directory admin = new Directory.Builder(httpTransport, JSON_FACTORY, credential)
                .setApplicationName("Test")
                .setHttpRequestInitializer(credential).build();


        Users users = admin.users().list().setDomain("mydomain.org").execute();

我在最后一行收到这个

错误

{
  "code" : 403,
  "errors" : [ {
    "domain" : "global",
    "message" : "Not Authorized to access this resource/api",
    "reason" : "forbidden"
  } ],
  "message" : "Not Authorized to access this resource/api"
}
    at com.google.api.client.googleapis.json.GoogleJsonResponseException.from(GoogleJsonResponseException.java:145)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:113)
    at com.google.api.client.googleapis.services.json.AbstractGoogleJsonClientRequest.newExceptionOnError(AbstractGoogleJsonClientRequest.java:40)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest$1.interceptResponse(AbstractGoogleClientRequest.java:312)
    at com.google.api.client.http.HttpRequest.execute(HttpRequest.java:1045)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)

如果我取消注释注释行 (.setServiceAccountUser("admin@mydomain.org")),则会收到不同的错误

    Exception in thread "main" com.google.api.client.auth.oauth2.TokenResponseException: 400 Bad Request
{
  "error" : "access_denied"
}
    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:269)
    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:858)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:410)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.executeUnparsed(AbstractGoogleClientRequest.java:343)
    at com.google.api.client.googleapis.services.AbstractGoogleClientRequest.execute(AbstractGoogleClientRequest.java:460)

我的帐户 (admin@mydomain.org) 是超级管理员。我怀疑服务帐户需要被授予用户 API 范围的访问权限。但是我找不到可以授予此访问权限的位置。我的 Google CPanel 有一个经典的 UI 模式。而且我在高级工具中没有“管理客户端 API 访问”页面。

我也不确定我应该在.setApplicationName("Test") 使用什么作为应用程序名称。

感谢您的帮助

【问题讨论】:

    标签: google-api google-api-java-client google-admin-sdk


    【解决方案1】:

    Google Directory API 可与 Compute Engine 默认服务帐户配合使用,您无需在域范围内设置 Google Drive。唯一的事情:您必须设置 serviceAccountUser,这在基于 JSON 的凭据中不受支持。所以你可以

    • 使用 P12 键
    • 带有解决方法的用户 JSON 凭据:

    制作凭证副本:

    import static com.google.api.client.googleapis.util.Utils.getDefaultJsonFactory;
    import static com.google.api.client.googleapis.util.Utils.getDefaultTransport;
    
    private static final String APPLICATION_NAME = "AnyAppName";
    
    private final List<String> SCOPES = ImmutableList.of(
            DirectoryScopes.ADMIN_DIRECTORY_GROUP_MEMBER, DirectoryScopes.ADMIN_DIRECTORY_USER, DirectoryScopes.ADMIN_DIRECTORY_GROUP);
    
    private Directory service;
    
    @PostConstruct
    void init() throws GeneralSecurityException, IOException {
        GoogleCredential credential;
        try (InputStream is = new FileInputStream("./config/client_secret.json")) {
            credential = GoogleCredential.fromStream(is);
        }
        GoogleCredential credentialWithUser = new GoogleCredential.Builder()
                .setTransport(getDefaultTransport())
                .setJsonFactory(getDefaultJsonFactory())
                .setServiceAccountUser("admin@yourdomain.ru")  // <--- mail of domain's admin
                .setServiceAccountId(credential.getServiceAccountId())
                .setServiceAccountScopes(SCOPES)
                .setServiceAccountPrivateKey(credential.getServiceAccountPrivateKey())
                .setServiceAccountPrivateKeyId(credential.getServiceAccountPrivateKeyId())
                .setTokenServerEncodedUrl(credential.getTokenServerEncodedUrl()).build();
    
        service = new Directory.Builder(getDefaultTransport(), getDefaultJsonFactory(), credentialWithUser).setApplicationName(APPLICATION_NAME).build();
    }
    
     public void members() throws IOException {
        Members members = service.members().list("groupName@yourdomain.ru").execute();
        System.out.println(members);
     }
    

    对于我的trial G Suite account,它可以工作!

    【讨论】:

      【解决方案2】:

      我遇到了完全相同的问题,并被困在this sample

      对我有什么帮助: 1/ 正如 Jay Lee 所建议的那样,我没有 Delegate domain-wide authority to your service account。但在那之后,我仍然遇到了问题。 2/ 然后,根据this post,调用 setServiceAccountUser(yourAdminAccount@yourDomain.com) 是强制性的。

      【讨论】:

        【解决方案3】:

        您可以转到管理控制台中的“安全”设置 (admin.google.com/AdminHome?chromeless=1&pli=1#SecuritySettings:);然后单击高级设置 > 管理第三方 OAuth 客户端访问。在此映射您的客户端 ID(从 oath2 的 API 访问下的 appconsole code.google.com/apis/console 生成)和“一个或多个 API 范围”之后。使用那里提到的逗号分隔范围。对于谷歌目录,您可以使用https://www.googleapis.com/auth/admin.directory.group,https://www.googleapis.com/auth/admin.directory.user

        希望在此之后它可以工作:)

        【讨论】:

        • 我有经典的管理控制台。这些页面位于其他位置。
        • 我正在使用试用帐户,但没有获得此选项,只是说“管理 OAuth 客户端访问”。是因为试用还是需要一些配置
        【解决方案4】:

        您可以按照Google Drive domain-wide documentation 中的说明授予服务帐户访问控制面板中某些范围的权限。只需使用 Admin SDK 范围。

        应用程序名称用于请求的 User-Agent 标头中,因此并不太重要,只需使用您的应用程序名称和版本即可。

        【讨论】:

        • 感谢您的回复。我找不到这个“管理第三方 OAuth 客户端访问”。如 Google Drive 文档中所述,我的控制面板中的高级工具中的项目。可能我需要以某种方式启用它?
        • 查看说明:support.google.com/a/bin/answer.py?hl=en&answer=162106。听起来您可能启用了新的管理控制台。
        • 我找不到这个“管理客户端 API 访问”页面。我添加了一张我的高级工具的图片。可能我需要启用一些东西?
        • 您使用的是什么版本的 Google Apps? (教育、商业、免费/标准)?
        • 我使用的是 Google Apps 合作伙伴版
        猜你喜欢
        • 2013-08-24
        • 2017-03-06
        • 2014-12-14
        • 2021-10-30
        • 2022-10-17
        • 1970-01-01
        • 2014-11-09
        • 2017-10-31
        • 2018-03-03
        相关资源
        最近更新 更多