【问题标题】:Google Sheets java sdk oAuth unauthorized after some hours (spring boot)Google Sheets java sdk oAuth 几个小时后未经授权(春季启动)
【发布时间】:2017-10-12 08:47:42
【问题描述】:

我按照Java Quistart Tutorial for Sheets API成功创建了一个spring boot Serviceclass,以便在google sheet上写字

我的问题是授权没有更新,所以在通过浏览器第一次成功认证后,几个小时后我得到 401 未授权。 如何在不重新发出浏览器登录的情况下自动更新令牌?

代码下方,提前致谢

import com.google.api.client.auth.oauth2.Credential;
import com.google.api.client.extensions.java6.auth.oauth2.AuthorizationCodeInstalledApp;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver;
import com.google.api.client.extensions.jetty.auth.oauth2.LocalServerReceiver.Builder;
import com.google.api.client.googleapis.auth.oauth2.GoogleAuthorizationCodeFlow;
import com.google.api.client.googleapis.auth.oauth2.GoogleClientSecrets;
import com.google.api.client.googleapis.javanet.GoogleNetHttpTransport;
import com.google.api.client.http.HttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.sheets.v4.Sheets;
import com.google.api.services.sheets.v4.SheetsScopes;
import com.google.api.services.sheets.v4.model.AppendValuesResponse;
import com.google.api.services.sheets.v4.model.ValueRange;

@Service
public class GoogleSheetsServiceImpl implements GoogleSheetsService {

    private static final Log LOGGER = LogFactory.getLog(GoogleSheetsServiceImpl.class);

    /** Application name. */
    @Value("${google-sheets.application-name}")
    private String applicationName;

    /** Directory to store user credentials for this application. */
    private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"),
            ".credentials/sheets.googleapis.com-orders");

    /** Global instance of the {@link FileDataStoreFactory}. */
    private FileDataStoreFactory dataStoreFactory;

    /** Global instance of the JSON factory. */
    private JsonFactory jsonFactory;

    /** Global instance of the HTTP transport. */
    private HttpTransport httpTransport;

    /**
     * Global instance of the scopes required by this quickstart.
     *
     * If modifying these scopes, delete your previously saved credentials at
     * ~/.credentials/sheets.googleapis.com-java-quickstart
     */
    private List<String> scopes;

    /** Sheet service. */
    private Sheets sheetsService;

    public GoogleSheetsServiceImpl() throws Throwable {
        // init
        try {
            this.jsonFactory = JacksonFactory.getDefaultInstance();
            this.scopes = Arrays.asList(SheetsScopes.SPREADSHEETS);
            this.httpTransport = GoogleNetHttpTransport.newTrustedTransport();
            this.dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);
        } catch (Throwable t) {
            LOGGER.error("Error on init Google Sheets Service: " + t.getMessage());
            throw t;
        }

        // get sheet service
        Credential credential = this.authorize();
        this.sheetsService = new Sheets.Builder(this.httpTransport, this.jsonFactory, credential)
                .setApplicationName(this.applicationName).build();
    }

    public void appendValueRangeToGoogleSheet(String spreadsheetId, String range, ValueRange valueRange)
            throws IOException {

        // append line
        Sheets.Spreadsheets.Values.Append request = sheetsService.spreadsheets().values()
                .append(spreadsheetId, range, valueRange).setValueInputOption("RAW");
        AppendValuesResponse response = request.execute();
    }

    /**
     * Creates an authorized Credential object.
     * 
     * @return an authorized Credential object.
     * @throws IOException
     */
    private Credential authorize() throws IOException {
        // Load client secrets.
        InputStream in = GoogleSheetsServiceImpl.class.getResourceAsStream("/google_sheets/client_secret.json");
        GoogleClientSecrets clientSecrets = GoogleClientSecrets.load(this.jsonFactory, new InputStreamReader(in));

        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(this.httpTransport, this.jsonFactory,
                clientSecrets, this.scopes).setDataStoreFactory(this.dataStoreFactory).setAccessType("online").build();
        LocalServerReceiver.Builder localServerReceiverBuilder = new Builder();
        localServerReceiverBuilder.setHost("localhost");
        localServerReceiverBuilder.setPort(46228);
        Credential credential = new AuthorizationCodeInstalledApp(flow, localServerReceiverBuilder.build())
                .authorize("user");
        LOGGER.info("Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
        return credential;
    }

}

编辑:

解决了修改 GoogleAuthorizationCodeFlow 对象的构建如下:

GoogleAuthorizationCodeFlow flow = new GoogleAuthorizationCodeFlow.Builder(this.httpTransport, this.jsonFactory,
            clientSecrets, this.scopes).setDataStoreFactory(this.dataStoreFactory).setAccessType("offline")
                    .setApprovalPrompt("force")
                    .addRefreshListener(
                            new DataStoreCredentialRefreshListener(credentialUserId, this.dataStoreFactory))
                    .build();

【问题讨论】:

  • 我认为draw.io 的人可能有同样的问题(根据我作为用户的经验)
  • 我是否使用了错误的方法?我试图检查如何使用 Api-Key 但我没有找到任何示例
  • 我不知道答案。我将在这个问题上开始赏金,以引起其他可能知道它的人的更多关注
  • 我实际上在第一次尝试时得到了 401 Unathorized...我如何确定我得到了正确的 JSON 文件?

标签: java spring-boot google-sheets-api


【解决方案1】:

有一个名为刷新令牌的概念,它似乎适合您的需求。

您可以在这个问题中找到很好的描述: https://stackoverflow.com/a/7209263/4988996

编辑:根据您的评论,我发现谷歌有 DataStoreCredentialRefreshListener

使用凭据访问受保护的资源。如果适用,将使用刷新令牌自动刷新过期的访问令牌。确保使用 DataStoreCredentialRefreshListener 并使用 Credential.Builder.addRefreshListener(CredentialRefreshListener) 为凭据设置它。

结帐:https://developers.google.com/api-client-library/java/google-oauth-java-client/oauth2

  static void addDataStoreCredentialRefreshListener(
      Credential.Builder credentialBuilder, String userId, DataStoreFactory dataStoreFactory)
      throws IOException {
    credentialBuilder.addRefreshListener(
        new DataStoreCredentialRefreshListener(userId, dataStoreFactory));
  }

【讨论】:

  • 感谢您的回复,您知道是否有任何使用 google sheet java sdk 准备好的示例?
  • 根据您的评论编辑了答案。看看吧。
  • @user4330585 你试过这个解决方案吗?任何反馈?赏金今天到期
  • @user4330585 我没有时间尝试这些。答案看起来并不完美,但我可能会奖励赏金,因为它是最好的
  • 我将其作为已接受的答案进行了检查。我还必须对他构建的 GoogleAuthorizationCodeFlow 进行修改,但答案帮助我找到了解决方案。非常感谢!
猜你喜欢
  • 2019-09-09
  • 2021-03-31
  • 2011-05-15
  • 1970-01-01
  • 1970-01-01
  • 2015-01-29
  • 2016-01-28
  • 2021-06-15
  • 2020-01-11
相关资源
最近更新 更多