【问题标题】:YouTube Data API V3 - automate authorisation process instead of manual interventionYouTube Data API V3 - 自动化授权过程而不是人工干预
【发布时间】:2017-12-04 00:59:53
【问题描述】:

我正在使用 YouTube Data API V3 将视频上传到我的 youtube 频道。提供的示例代码中的授权码需要人工干预授权过程。每次我重新启动服务器时,它都会打开浏览器并要求我进行身份验证和权限。对于我的 Windows PC,这很好,但我打算将此代码部署到我只有 SSH 访问权限的远程 Linux 机器上。

有没有办法让这个过程自动化?就像通过使用普通凭据(用户名和密码)访问 API 或进行一次此过程(永久身份验证/授权)一样。

我确实阅读了一些关于这个主题的线程,这些线程指向使用刷新令牌。

【问题讨论】:

  • 你解决了这个问题吗?

标签: java oauth youtube youtube-api youtube-data-api


【解决方案1】:

可能有点晚了……

1) 在Google Developers Console 中创建新项目。

2) 创建 oauth 2.0 客户 ID。在应用程序类型中选择 - 其他。

3) 下载 json 文件,将其重命名为“client_secret.json”并将其添加到 /resources 文件夹(用于 Gradle 项目)。

4) 创建java文件并添加以下代码:

public class YoutubeAuth {

    private static final String CLIENT_SECRETS= "/client_secret.json";

    private static final Collection<String> SCOPES =
            Arrays.asList("https://www.googleapis.com/auth/youtube.readonly");

    private static FileDataStoreFactory dataStoreFactory;

    private static final java.io.File DATA_STORE_DIR =
            new java.io.File(System.getProperty("user.home"), ".store/youtube");

    private static final String APPLICATION_NAME = "Custom Application Name";

    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

    /**
     * Create an authorized Credential object.
     *
     * @return an authorized Credential object.
     * @throws IOException
     */
    private static Credential authorize(final NetHttpTransport httpTransport) throws IOException {

       // Load client secrets.
        InputStream in = YoutubeAuth.class.getResourceAsStream(CLIENT_SECRETS);
        GoogleClientSecrets clientSecrets =
                GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));
        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow.Builder(httpTransport, JSON_FACTORY, clientSecrets, SCOPES)
                        .setDataStoreFactory(dataStoreFactory)
                        .build();
        return new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
    }

    /**
     * Build and return an authorized API client service.
     *
     * @return an authorized API client service
     * @throws GeneralSecurityException, IOException
     */
    public static YouTube getService() throws GeneralSecurityException, IOException {
        final NetHttpTransport httpTransport = GoogleNetHttpTransport.newTrustedTransport();

        dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);

        Credential credential = authorize(httpTransport);


        return new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

}

注意这行代码:

private static FileDataStoreFactory dataStoreFactory;
private static final java.io.File DATA_STORE_DIR = new java.io.File(System.getProperty("user.home"),".store/youtube");

到这个方法里面的 authorize() 方法:

.setDataStoreFactory(dataStoreFactory)

在 getService() 方法中的这个方法:

dataStoreFactory = new FileDataStoreFactory(DATA_STORE_DIR);


YouTube youtubeService = LfkYoutubeAuth.getService();
...
// some other code
---

所以你可以像这样使用 Youtube 服务

【讨论】:

  • 2) 创建 oauth 2.0 客户 ID。在应用程序类型中选择 - 其他。 我在其中看不到 Other 选项。
  • 也许有些事情发生了变化。您可以在 android 和 web 应用程序或其他东西之间进行检查。
  • 我想知道为什么我们需要这种手动干预来授权。如何自动化。
【解决方案2】:

通常我会说您应该使用服务帐户,然后您根本不需要执行身份验证过程。但是 YouTube API 不支持服务帐户身份验证。

我无法解释为什么在重新启动后需要刷新您的身份验证。您的代码应该保存包含刷新令牌的凭据文件,刷新令牌即使在重新启动后也应该继续工作。我会冒险猜测您的代码有问题。

这是一个Java Quickstart 示例,它显示了如何保存凭据。如果您需要任何帮助来为 YouTube 更改它,请告诉我,它适用于 people api 而不是 Youtube。当服务器重新启动时,这些凭据不会被删除。

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.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.jackson2.JacksonFactory;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.util.store.FileDataStoreFactory;
import com.google.api.services.people.v1.PeopleService;
import com.google.api.services.people.v1.PeopleScopes;
import com.google.api.services.people.v1.model.ListConnectionsResponse;
import com.google.api.services.people.v1.model.Person;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.util.Arrays;
import java.util.List;

public class Quickstart {
    /** Application name. */
    private static final String APPLICATION_NAME =
        "People API Java Quickstart";

    /** 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/people.googleapis.com-java-quickstart");

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

    /** Global instance of the JSON factory. */
    private static final JsonFactory JSON_FACTORY =
        JacksonFactory.getDefaultInstance();

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

    /** Global instance of the scopes required by this quickstart.
     *
     * If modifying these scopes, delete your previously saved credentials
     * at ~/.credentials/people.googleapis.com-java-quickstart
     */
    private static final List<String> SCOPES =
        Arrays.asList(PeopleScopes.CONTACTS_READONLY);

    static {
        try {
            HTTP_TRANSPORT = GoogleNetHttpTransport.newTrustedTransport();
            DATA_STORE_FACTORY = new FileDataStoreFactory(DATA_STORE_DIR);
        } catch (Throwable t) {
            t.printStackTrace();
            System.exit(1);
        }
    }

    /**
     * Creates an authorized Credential object.
     * @return an authorized Credential object.
     * @throws IOException
     */
    public static Credential authorize() throws IOException {
        // Load client secrets.
        InputStream in =
            Quickstart.class.getResourceAsStream("/client_secret.json");
        GoogleClientSecrets clientSecrets =
            GoogleClientSecrets.load(JSON_FACTORY, new InputStreamReader(in));

        // Build flow and trigger user authorization request.
        GoogleAuthorizationCodeFlow flow =
                new GoogleAuthorizationCodeFlow.Builder(
                        HTTP_TRANSPORT, JSON_FACTORY, clientSecrets, SCOPES)
                .setDataStoreFactory(DATA_STORE_FACTORY)
                .setAccessType("offline")
                .build();
        Credential credential = new AuthorizationCodeInstalledApp(
            flow, new LocalServerReceiver()).authorize("user");
        System.out.println(
                "Credentials saved to " + DATA_STORE_DIR.getAbsolutePath());
        return credential;
    }

    /**
     * Build and return an authorized People client service.
     * @return an authorized People client service
     * @throws IOException
     */
    public static PeopleService getPeopleService() throws IOException {
        Credential credential = authorize();
        return new PeopleService.Builder(HTTP_TRANSPORT, JSON_FACTORY, credential)
                .setApplicationName(APPLICATION_NAME)
                .build();
    }

    public static void main(String [] args) throws IOException {
        PeopleService service = getPeopleService();

        // Request 10 connections.
        ListConnectionsResponse response = service.people().connections()
                .list("people/me")
                .setPageSize(10)
                .setPersonFields("names,emailAddresses")
                .execute();

        // Print display name of connections if available.
        List<Person> connections = response.getConnections();
        if (connections != null && connections.size() > 0) {
            for (Person person : connections) {
                List<Name> names = person.getNames();
                if (names != null && names.size() > 0) {
                    System.out.println("Name: " + person.getNames().get(0)
                            .getDisplayName());
                } else {
                    System.out.println("No names available for connection.");
                }
            }
        } else {
            System.out.println("No connections found.");
        }
    }

}

回答:至于您的服务器问题以及如何使其自动化。答案是你不能。没有浏览器窗口就无法进行身份验证。您应该在您的 Windows 电脑上进行身份验证,将我所说的凭据文件复制到您的服务器。

【讨论】:

  • 谢谢!你能告诉我如何使用刷新令牌来避免重复的身份验证过程吗?
  • 图书馆应该会为您处理。它不再请求是吗?
  • 实际上我确实使用了 Auth 类进行授权,但是在 1 小时或之后它要求我再次授权。有什么办法可以阻止这种情况。我尝试了将凭据文件复制到服务器的解决方案,它可以正常工作。但是一小时后我必须再次重复这个过程。
  • 访问令牌仅持续一个小时,然后需要使用刷新令牌来获取新的访问令牌。抱歉,我不能告诉你 ruby​​ 库是否可以这样做。
  • 感谢您的快速回复。这意味着我需要每隔一小时更改凭据文件并将其上传到服务器。
【解决方案3】:

您如何存储您的凭据?如果您的服务器关闭,您的凭据是否也会随之丢失?您可以考虑将其存储在外部数据库中,或者如果它是 Web 应用程序,您可以将其存储为 cookie。

刷新令牌仅发布一次(在第一次初始身份验证期间),因此如果您之前已经授权过您的帐户,则需要访问您的应用权限并将其删除。然后再次尝试授权,并保存该刷新令牌。如果您正确保存了刷新令牌(使用 cookie/数据库/其他),那么您将在请求时获得一个新的访问令牌。使用此方法,您不必每次都重新授权

【讨论】:

  • 你能一步一步解释这个过程吗?
猜你喜欢
  • 1970-01-01
  • 2015-09-14
  • 1970-01-01
  • 1970-01-01
  • 1970-01-01
  • 2014-11-05
  • 2018-11-03
  • 1970-01-01
  • 2015-12-09
相关资源
最近更新 更多