从使用 YouTube 数据 API 的个人项目中删除 Google 未经验证的警告

Posted

技术标签:

【中文标题】从使用 YouTube 数据 API 的个人项目中删除 Google 未经验证的警告【英文标题】:Removing Google unverified warning from personal project that uses the YouTube Data API 【发布时间】:2021-01-12 03:30:54 【问题描述】:

我正在制作一个不供公众使用的个人项目。该项目使用 YouTube 数据 API v3。当我运行代码时,我看到了这个警告:

> Task :ApiExample.main()
2020-09-25 14:52:25.740:INFO::Logging to STDERR via org.mortbay.log.StdErrLog
2020-09-25 14:52:25.748:INFO::jetty-6.1.26
2020-09-25 14:52:25.796:INFO::Started SocketConnector@localhost:*****
Please open the following address in your browser:

我不确定 localhost 是什么以及数字代表什么,所以我用星号替换了它,以防它应该是私有的。

当我打开下面的链接时,系统会提示我登录我的 Google 帐户,然后显示此屏幕。

此应用未经验证 此应用尚未经过 Google 验证。只有在您了解并信任开发者的情况下才能继续。

如果您是开发者,请提交验证请求以移除此屏幕。了解更多

Google 尚未审核此应用,因此无法确认其真实性。未经验证的应用程序可能会对您的个人数据构成威胁。了解更多

我不想经历整个验证过程,因为这本身并不是一个真正的“应用程序”。我只是在玩弄 API 来了解它是如何工作的。有什么方法可以绕过验证过程,这样我就可以使用 API 进行练习,而无需让 Google 批准我制作的随机项目?我不想每次使用该程序时都必须在线登录。

编辑

如果我正确理解 cmets,我每次运行程序时都必须登录的原因是因为我使用 OAuth 2.0,而我只需要使用 API 密钥,因为我的程序不需要访问我的特定帐户。 authorization credentials 页面上强烈暗示了这一点,该页面指出:

此 API 支持两种类型的凭据。创建适合您项目的凭据:

OAuth 2.0:每当您的应用程序请求私有用户数据时,它必须随请求一起发送 OAuth 2.0 令牌。您的应用程序首先发送一个客户端 ID,并且可能还发送一个客户端密码以获取令牌。您可以为 Web 应用程序、服务帐户或已安装的应用程序生成 OAuth 2.0 凭据。

API 密钥:不提供 OAuth 2.0 令牌的请求必须发送 API 密钥。密钥标识您的项目并提供 API 访问、配额和报告。

当我第一次创建项目时,我只打算使用 API 密钥,而不是 OAuth 2.0 凭据,因为它在该页面上显示。但是,Java quickstart 没有提供仅使用 API 密钥的选项。相反,那里显示的演示代码看起来像this:

/**
 * Sample Java code for youtube.channels.list
 * See instructions for running these code samples locally:
 * https://developers.google.com/explorer-help/guides/code_samples#java
 */

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.googleapis.json.GoogleJsonResponseException;
import com.google.api.client.http.javanet.NetHttpTransport;
import com.google.api.client.json.JsonFactory;
import com.google.api.client.json.jackson2.JacksonFactory;

import com.google.api.services.youtube.YouTube;
import com.google.api.services.youtube.model.ChannelListResponse;

import java.io.IOException;
import java.io.InputStream;
import java.io.InputStreamReader;
import java.security.GeneralSecurityException;
import java.util.Arrays;
import java.util.Collection;

public class ApiExample 
    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 final String APPLICATION_NAME = "API code samples";
    private static final JsonFactory JSON_FACTORY = JacksonFactory.getDefaultInstance();

    /**
     * Create an authorized Credential object.
     *
     * @return an authorized Credential object.
     * @throws IOException
     */
    public static Credential authorize(final NetHttpTransport httpTransport) throws IOException 
        // Load client secrets.
        InputStream in = ApiExample.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)
            .build();
        Credential credential =
            new AuthorizationCodeInstalledApp(flow, new LocalServerReceiver()).authorize("user");
        return credential;
    

    /**
     * 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();
        Credential credential = authorize(httpTransport);
        return new YouTube.Builder(httpTransport, JSON_FACTORY, credential)
            .setApplicationName(APPLICATION_NAME)
            .build();
    

    /**
     * Call function to create API service object. Define and
     * execute API request. Print API response.
     *
     * @throws GeneralSecurityException, IOException, GoogleJsonResponseException
     */
    public static void main(String[] args)
        throws GeneralSecurityException, IOException, GoogleJsonResponseException 
        YouTube youtubeService = getService();
        // Define and execute the API request
        YouTube.Channels.List request = youtubeService.channels()
            .list("snippet,contentDetails,statistics");
        ChannelListResponse response = request.setId("UC_x5XG1OV2P6uZZ5FSM9Ttw").execute();
        System.out.println(response);
    

在上述代码示例中,client_secret.json 是包含我的 OAuth 2.0 凭据的 JSON 文件。综上所述,我相信我可以将我的问题重申如下:如何仅使用 API 密钥而不是包含我的 OAuth 2.0 凭据的 JSON 文件来编写上述代码示例?

编辑

我已将 main 方法替换为以下内容:

public static void main(String[] args)
        throws GeneralSecurityException, IOException, GoogleJsonResponseException 
    Properties properties = new Properties();
    try 
        InputStream in = ApiExample.class.getResourceAsStream("/" + "youtube.properties");
        properties.load(in);

     catch (IOException e) 
        System.err.println("There was an error reading " + "youtube.properties" + ": " + e.getCause()
                + " : " + e.getMessage());
        System.exit(1);
    
    YouTube youtubeService = getService();
    // Define and execute the API request
    YouTube.Channels.List request = youtubeService.channels()
            .list("snippet,contentDetails,statistics");
    String apiKey = properties.getProperty("youtube.apikey");
    request.setKey(apiKey);
    ChannelListResponse response = request.setId("UC_x5XG1OV2P6uZZ5FSM9Ttw").execute();
    System.out.println(response);


但是,每当我运行代码时,我仍然需要登录。

编辑

哎呀,我还在上面的代码示例中调用getService() 方法。以下作品:

YouTube youtubeService = new YouTube.Builder(new NetHttpTransport(), new JacksonFactory(), new HttpRequestInitializer() 
            public void initialize(HttpRequest request) throws IOException 
            
        ).setApplicationName(APPLICATION_NAME).build();

问题已解决。

【问题讨论】:

只需点击Go to GradleDemo (Unsafe) @stvar 对不起,如果我不清楚;我将编辑我的问题以澄清。我正在寻找某种方式来运行程序,而无需先上网登录。 这在设计上是不可能的。您必须登录一次——从 API 获取(长期)刷新令牌和(短期)访问令牌。那么就不需要再登录了,除非你丢弃了之前获得的刷新令牌。但是当您打算只读取公共视频元数据时,OAuth 2.0 授权不是必需的。 W.r.t.刷新/访问令牌确实读取了top-level description of them I gave a while ago,然后开始吸收其中提到的文档。 @stvar 我已经编辑了我的问题。我不确定我说的是否正确,但我相信这可能会更容易解决问题。 【参考方案1】:

如果您只打算使用Channels.list API 端点来获取公共频道元数据,那么绝对不需要使用 OAuth 2.0 授权(以及隐含的一次性身份验证) .

YouTube.Channels.list 类具有此方法,允许您设置由 Google(通过其云控制台)提供的 API 密钥(作为私有数据):

setKey

public YouTube.Channels.List setKey(java.lang.String key)

从班级复制的描述:YouTubeRequest API 密钥。您的 API 密钥可识别您的项目并为您提供 API 访问权限、配额和报告。除非您提供 OAuth 2.0 令牌,否则必填。

覆盖: setKey在课堂上YouTubeRequest&lt;ChannelListResponse&gt;

您可以查看来自 Google 的示例源文件 GeolocationSearch.java 以了解 setKey 的实际效果:

// Set your developer key from the  Google Cloud Console  for
// non-authenticated requests. See:
//  https://cloud.google.com/console 
String apiKey = properties.getProperty("youtube.apikey");
search.setKey(apiKey);

在您的情况下,上述代码的工作方式完全相同。只是您必须将setKey 应用于您的request(对象)变量。

【讨论】:

以上示例中的youtube.apikey 是什么?它是实际数字键、文件名或其他内容的替代品吗? 如果您查看代码,您会看到 API 密钥是从名为 youtube.propertiesproperties 文件中读取的。这对您来说并不是真正必要的,但除此之外,这是一个很好的做法(不要让您的 API 密钥在源代码本身中出现)。您可能只是拥有类似request.setKey(YOUR_APP_KEY) 的东西,其中YOUR_APP_KEY 的类型为String,并拥有您从Google 获得的API 密钥。 我改变了我的主要方法,见上面的编辑。还没有解决我的问题,每次运行代码我还是要登录。 但是您仍然调用 getService(您保持不变),这将启动 OAuth 流程。 我引用的示例代码没有像 authorize 这样的调用,它本身会启动 OAuth 流程。

以上是关于从使用 YouTube 数据 API 的个人项目中删除 Google 未经验证的警告的主要内容,如果未能解决你的问题,请参考以下文章

从 YouTube API 响应中选择特定键

访问未配置。 YouTube 数据 API 尚未在项目 608941808256 中使用

使用 YouTube API v3 检索播放列表中的项目数

如何使用 python 从 youtube v3 api 修复 json?

Youtube API - 没有频道名称

使用 YouTube API 从用户提供的搜索词中获取 YouTube 视频 ID