【问题标题】:Java, Google Drive : Why does GoogleAPI sometime does not give refresh token when authorized?Java、Google Drive:为什么 Google API 有时在授权时不提供刷新令牌?
【发布时间】:2015-09-15 07:42:26
【问题描述】:

我有一个 Spring-MVC 项目,其中集成了 Google Drive 功能以将附件上传到 Google Drive。为此,我使用了他们的示例代码并对其进行了修改。现在,每当我授权时,我都会获得一个 Credential 对象,并将访问令牌和刷新令牌保存在数据库中。

问题是有时 Google 决定给我刷新令牌,有时却出乎意料地没有。这导致了一个问题,因为在发出请求时没有刷新令牌,我得到一个 401。

那么,有时我没有获得刷新令牌时这种异想天开的性质是什么? 这是我用于授权、storeCredentials、getStoredCredentials 和保存文件的代码。

     @Override
        public Credential authorize() throws IOException {
            InputStream in =
                    DriveQuickstartImpl.class.getResourceAsStream("/client_secret.json");
            GoogleClientSecrets clientSecrets =
                    GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

            GoogleAuthorizationCodeFlow flow =
                    new GoogleAuthorizationCodeFlow.Builder(
                            HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                            .setDataStoreFactory(DATA_STORE_FACTORY)
                            .setAccessType("offline")
                            .build();
            Credential credential = new AuthorizationCodeInstalledApp(
                    flow, new com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver()).authorize("user");
            if (credential != null) {
                storeCredentials(credential);
                return credential;
            }
            return null;
        }

 @Override
    public void storeCredentials(Credential credential) {
        Person person = this.personService.getCurrentlyAuthenticatedUser();
        if (!(credential == null)) {
            person.setGoogleDrive(true);
            this.personService.updatePerson(person);
            GoogleDrive googleDrive = new GoogleDrive();
            googleDrive.setAccessToken(credential.getAccessToken());
            googleDrive.setRefreshToken(credential.getRefreshToken());
            this.googleDriveService.saveCredentials(googleDrive, person.getId());
        }
    }

  private Credential getStoredCredentials(Long groupAccountid) {
        try {
            GroupAccount groupAccount = this.groupAccountService.getGroupById(groupAccountid);
            Person person = this.personService.findPersonByUsername(groupAccount.getAdminUsername());
            if (person.isGoogleDrive()) {
                GoogleDrive googleDrive = this.googleDriveService.getUsersGoogleDrive(person.getId());
                GoogleCredential credential = new GoogleCredential.Builder().setJsonFactory(JSON_FACTORY)
                        .setTransport(HTTP_TRANSPORT).setClientSecrets(clientid, clientsecret).build();
                credential.setAccessToken(googleDrive.getAccessToken());
                credential.setRefreshToken(googleDrive.getRefreshToken());
                return credential;
            }
        } catch (Exception e) {
            e.printStackTrace();
        }

        return null;

    }


 @Override
    public File insertFile(MultipartFile multipartFile, int noteid, Long groupAccountId, String folderId) {
        try {
            GroupAccount groupAccount = this.groupAccountService.getGroupById(groupAccountId);
            Person person = this.personService.findPersonByUsername(groupAccount.getAdminUsername());
            if (person.isGoogleDrive()) {
                Credential credential = getStoredCredentials(groupAccountId);
                Drive driveService = new Drive.Builder(HTTP_TRANSPORT, JSON_FACTORY, null).
                        setApplicationName(APPLICATION_NAME).
                        setHttpRequestInitializer(credential).build();

                File body = new File();
                body.setTitle(multipartFile.getOriginalFilename());
                body.setMimeType(multipartFile.getContentType());
                body.setOriginalFilename(multipartFile.getOriginalFilename());

                body.setParents(Arrays.asList(new ParentReference().setId(folderId)));
                InputStreamContent mediaContent = new InputStreamContent(multipartFile.getContentType(),
                        new BufferedInputStream(multipartFile.getInputStream()));
                try {
                    File file = driveService.files().insert(body, mediaContent).execute();
                    this.groupAttachmentsService.addGoogleDriveAttachment(file.getWebContentLink(), multipartFile.getOriginalFilename(),
                            file.getFileSize(), noteid, file.getId(), multipartFile);
                    insertPermission(driveService, file.getId(), "default", "anyone", "reader");
                    return file;
                } catch (Exception e) {
                    e.printStackTrace();
                    return null;
                }
            }
        } catch (Exception e) {
            return null;
        }

        return null;
    }

错误日志:

com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
  "code" : 401,
  "errors" : [ {
    "domain" : "global",
    "location" : "Authorization",
    "locationType" : "header",
    "message" : "Invalid Credentials",
    "reason" : "authError"
  } ],
  "message" : "Invalid Credentials"
}

我正在检查数据库中的值,我可以看到每当刷新令牌为空时,我都会收到 401,否则我可以上传文件。但是使用的代码总是一样的。你能帮忙的话,我会很高兴。非常感谢。

【问题讨论】:

  • 只有在提示用户同意屏幕时才会提供刷新令牌。您可以使用 setApprovalPrompt 来“强制”始终获取刷新令牌

标签: java file-upload google-api google-drive-api


【解决方案1】:

如果有人遇到问题,那么 setApprovalPrompt 设置为“强制”并将访问类型设置为“离线”是必要的。可以将授权码更改为我在下面给出的:

@Override
    public Credential authorize() throws IOException {
        InputStream in =
                DriveQuickstartImpl.class.getResourceAsStream("/client_secret.json");
        GoogleClientSecrets clientSecrets =
                GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        GoogleAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow.Builder(
                        HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                        .setDataStoreFactory(DATA_STORE_FACTORY)
                        .setAccessType("offline")
                        .setApprovalPrompt("force")
                        .build();
        Credential credential = new AuthorizationCodeInstalledApp(
                flow, new com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver()).authorize("user");
        if (credential != null) {
            storeCredentials(credential);
            return credential;
        }
        return null;
    }

如果需要任何帮助,请发表评论。

【讨论】:

  • 实际问题是谷歌只提供了一次刷新令牌(不是突然的,它不是随机的)。如果你没有保存它,除非你强迫它,否则它不会再给它。每次我认为强制暴露刷新令牌需要的次数会降低安全性。
猜你喜欢
  • 2017-10-10
  • 2013-06-03
  • 1970-01-01
  • 2016-10-13
  • 1970-01-01
  • 2017-10-17
  • 1970-01-01
  • 2019-02-16
  • 1970-01-01
相关资源
最近更新 更多