使用Google OAuth2进行非交互式授权

时间:2017-06-07 18:52:30

标签: authentication oauth-2.0 silent google-groups-api

我创建了一个Java应用程序,用于执行MS Active Directory与Google Groups的同步。它是非交互式应用程序,假设在晚上由cronjob执行。 它在我的笔记本电脑(DEV环境)上完美运行。 我的问题是,在第一次运行时,它弹出浏览器窗口,对话框要求授权访问Google API。点击"允许"按钮它愉快地进行到最后。 现在我需要将它移动到运行CentOS且没有浏览器的生产服务器上。 当我在此环境中运行我的应用程序时,它会打印以下消息:

Please open the following address in your browser:  
https://accounts.google.com/o/oauth2/auth?access_type=offline&client_id=520105804541-c7d7bfki88qr8dbkv6oahp22i3oq1jq0.apps.googleusercontent.com&redirect_uri=http://localhost:50089/Callback&response_type=code&scope=https://www.googleapis.com/auth/admin.directory.group.member%20https://www.googleapis.com/auth/admin.directory.orgunit%20https://www.googleapis.com/auth/admin.directory.device.mobile.action%20https://www.googleapis.com/auth/admin.directory.orgunit.readonly%20https://www.googleapis.com/auth/admin.directory.userschema%20https://www.googleapis.com/auth/admin.directory.device.chromeos%20https://www.googleapis.com/auth/admin.directory.notifications%20https://www.googleapis.com/auth/admin.directory.device.chromeos.readonly%20https://www.googleapis.com/auth/admin.directory.device.mobile%20https://www.googleapis.com/auth/admin.directory.group.readonly%20https://www.googleapis.com/auth/admin.directory.group.member.readonly%20https://www.googleapis.com/auth/admin.directory.userschema.readonly%20https://www.googleapis.com/auth/admin.directory.user.alias%20https://www.googleapis.com/auth/admin.directory.user.security%20https://www.googleapis.com/auth/admin.directory.device.mobile.readonly%20https://www.googleapis.com/auth/admin.directory.user%20https://www.googleapis.com/auth/admin.directory.user.readonly%20https://www.googleapis.com/auth/admin.directory.user.alias.readonly%20https://www.googleapis.com/auth/admin.directory.group%20https://www.googleapis.com/auth/apps.groups.settings

这台机器上没有浏览器,但是如果我尝试在另一个盒子上运行它,我收到错误400 - 请求无效。 原因很清楚,因为它重定向到localhost:50089并且没有人在另一台机器上侦听该端口。 浏览developers.google.com上的多个文档和示例我找到了一种通过创建服务帐户并为其生成主键来绕过对话框的方法。

    try {
        GoogleCredential cr = GoogleCredential
             .fromStream(new FileInputStream(keyFile))
             .createScoped(SCOPES);
        Directory directory = new Directory.Builder(httpTransport, jsonFactory, cr)
.setApplicationName(config.getProperty("google.application.name")).build();
    } catch (IOException ex) {
       LOG.error("Failed to establish access credentials : ", ex.getMessage());
    }

它确实读取了密钥并创建了Directory实例,但是对它的任何请求都会产生403响应代码

  

{" code" :403,"错误" :[{" domain" :"全球","消息" :   "未授权访问此资源/ api","原因" :"禁止"
  }]," message" :"未授权访问此资源/ api" }"

但我已将此帐户的所有权限委派给服务帐户。不知道我还能做些什么。 如果有人能帮助我解决这个问题,我非常感激。

1 个答案:

答案 0 :(得分:4)

我找到了解决方案。问题是Google生成的JSON密钥没有设置服务帐户用户。你必须像这样手动完成:

        GoogleCredential cr = GoogleCredential
             .fromStream(new FileInputStream(keyFile))
             .createScoped(SCOPES);
        GoogleCredential.Builder builder = new GoogleCredential.Builder()
             .setTransport(httpTransport)
             .setJsonFactory(jsonFactory)
             .setServiceAccountScopes(SCOPES)
             .setServiceAccountId(cr.getServiceAccountId())
             .setServiceAccountPrivateKey(cr.getServiceAccountPrivateKey())
             .setServiceAccountPrivateKeyId(cr.getServiceAccountPrivateKeyId())
             .setTokenServerEncodedUrl(cr.getTokenServerEncodedUrl())
             .setServiceAccountUser(user);
        Directory directory = new Directory.Builder(
              httpTransport, jsonFactory, builder.build()) 
             .setApplicationName(config.getProperty("google.application.name")).build();