Google 图书 API 授权错误

Google Books API Auth errors

我正在构建一个 Android 应用程序并尝试将 Google 书籍 API 集成到我的应用程序中。 现在,登录工作。我收到同意屏幕,其中包含访问我帐户中的 Google 图书数据的请求。 我现在正尝试使用以下代码从我的图书馆中获取所有书架:

public class GetUsernameTask extends AsyncTask<String, Void, Void> {
    Activity mActivity;
    String mScope;
    String mEmail;

    public GetUsernameTask(Activity activity, String name, String scope) {
        this.mActivity = activity;
        this.mScope = scope;
        this.mEmail = name;
    }

    /**
     * Executes the asynchronous job. This runs when you call execute()
     * on the AsyncTask instance.
     */
    @Override
    protected Void doInBackground(String... params) {
        try {
            String token = fetchToken();
            if (token != null) {
                Log.i("TAG", "Got a token: " + token);
                // Use the token to access the user's Google data.
                String api_key = params[0];
                URL object = new URL("https://www.googleapis.com/books/v1/mylibrary/bookshelves?key=" + api_key);
                HttpsURLConnection connection = (HttpsURLConnection) object.openConnection();
                connection.setRequestProperty("Authorization", token);
                connection.setRequestMethod("GET");
                connection.setDoInput(true);
                Log.i("TAG", connection.getResponseMessage());
                InputStream is = connection.getErrorStream();
                BufferedReader reader = new BufferedReader(new InputStreamReader(is));
                String line;
                while ((line = reader.readLine()) != null) {
                    Log.i("TAG", line);
                }
            }
        } catch (IOException e) {
            Log.e("TAG", "Got an exception", e);
        }
        return null;
    }

    /**
     * Gets an authentication token from Google and handles any
     * GoogleAuthException that may occur.
     */
    protected String fetchToken() throws IOException {
        try {
            return GoogleAuthUtil.getToken(mActivity, mEmail, mScope);
        } catch (UserRecoverableAuthException userRecoverableException) {
            // GooglePlayServices.apk is either old, disabled, or not present
            // so we need to show the user some UI in the activity to recover.

            Log.i("TAG", "Nu! more exceptions", userRecoverableException);
        } catch (GoogleAuthException fatalException) {
            // Some other type of unrecoverable exception has occurred.
            // Report and log the error as appropriate for your app.
            Log.i("TAG", "Nu! more exceptions", fatalException);
        }
        return null;
    }
}

此代码来自 Google 文档 (https://developers.google.com/android/guides/http-auth)。

根据要求,我按照文档 (https://developers.google.com/books/docs/v1/using?hl=en#WorkingMyBookshelves) 的规定附加了“?key=api_key”,并且我也在 header 中指定了我的令牌。打印令牌时,它看起来像这样:xxxx.YQJ8nJimB8eeQOIdVkkg2WfkobsBkARzc2TWJL4d_2ipIQuJ4U9uFTvNNhye7i0474TbsA

我得到的结果令人惊讶;这是一个 401 HTTP 错误,即:

 {
  "error": {
   "errors": [
    {
     "domain": "global",
     "reason": "authError",
     "message": "Invalid Credentials",
     "locationType": "header",
     "location": "Authorization"
    }
   ],
   "code": 401,
   "message": "Invalid Credentials"
  }
}

作为 API 密钥,我尝试使用以下内容:

我还发现我的硬盘上有两个 debug.keystore 文件,一个在 C:\Android\ 中,一个在 ~\.android 中。我只是决定将两个 SHA-1 哈希添加到两个 Android 密钥(以及 OAuth 2.0 客户端 ID),希望它以某种方式使用其他密钥库 - 但无济于事。

我做错了什么?

我也尝试过使用 Google Play 服务库。这给出了不同的错误;但错误仍然存​​在。

我使用此代码(在 doInBackground 方法中)尝试使用所述 API:

try {
    Books service = new Books.Builder(AndroidHttp.newCompatibleTransport(), JacksonFactory.getDefaultInstance(), null).setGoogleClientRequestInitializer(new BooksRequestInitializer(api_key)).build();
    List<Bookshelf> shelves = service.mylibrary().bookshelves().list().execute().getItems();
}catch (Exception ex){
    Log.e("TAG", "Error while using Books", ex);
}

使用 Android 键,我收到 403 Forbidden HTTP 响应,消息为 "There is a per-IP or per-Referer restriction configured on your API key and the request does not match these restrictions. Please use the Google Developers Console to update your API key configuration if request from this IP or referer should be allowed."。但是,我在使用 Android API 键的任何地方都看不到任何 IP 限制。

使用服务器密钥,我收到 400 错误请求,可能是因为缺少令牌。

我做错了什么?我错过了什么?

在询问了一些与我关系密切的人后,我注意到我设置授权的方式 header。根据 Wiki (https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side),令牌前面有一个 "Type"。在 Google OAuth2 的情况下,此类型为 Bearer

因此,改变

connection.setRequestProperty("Authorization", token);

进入

connection.setRequestProperty("Authorization", "Bearer " + token);

成功了。编辑:显然,这是在这里指定的:https://developers.google.com/books/docs/v1/using?hl=en#query-params - 一直在页面底部的 header 下,我认为它不适合如此重要的东西。

至于 Google API,我现在意识到我没有在任何地方指定令牌。经过一番搜索,我发现您可以像这样设置 Oauth 令牌:

List<Bookshelf> shelves = service.mylibrary().bookshelves().list().setOauthToken(token).execute().getItems();

这给了我想要的结果。请注意:这是使用 Server 键完成的,而不是 Android 键。 Android 键仍然给我 403 ipRefererBlocked 错误。