4

我正在构建一个 Android 应用程序并尝试将 Google Books 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 )。

作为请求,我附加了“?key=api_key”,由文档(https://developers.google.com/books/docs/v1/using?hl=en#WorkingMyBookshelves)指定,我已经指定了我的令牌标题也是。打印令牌时,它看起来像这样: 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 Services 库。这会产生不同的错误;但仍然有错误。

我使用此代码(在 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 响应,并显示消息“在您的 API 密钥上配置了 per-IP 或 per-Referer 限制,并且请求与这些限制不匹配。请使用 Google Developers Console 更新如果应允许来自此 IP 或引用者的请求,则您的 API 密钥配置。”。但是,我在任何地方都看不到使用 Android API 密钥的任何 IP 限制。

使用服务器密钥,我收到 400 Bad Request,可能是因为缺少令牌。

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

4

1 回答 1

2

在询问了一些与我关系密切的人之后,我注意到我设置 Authorization 标头的方式。根据 Wiki ( https://en.wikipedia.org/wiki/Basic_access_authentication#Client_side ),令牌前面有一个“类型”。对于 Google OAuth2,此类型为Bearer.

因此,改变

connection.setRequestProperty("Authorization", token);

进入

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

成功了。编辑:显然,这是在此处指定的:https ://developers.google.com/books/docs/v1/using?hl=en#query-params - 一直位于页面底部我不使用的标题下感觉不适合如此重要的东西。

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

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

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

于 2016-01-06T22:33:08.663 回答