8

在连接到 Google+ 后,我正在使用以下代码获取访问令牌,以获取个人资料信息和电子邮件:

String sAccessToken = GoogleAuthUtil.getToken(this,mPlusClient.getAccountName() + "",
                          "oauth2:" + Scopes.PLUS_PROFILE + " 
                          https://www.googleapis.com/auth/userinfo.profile 
                          https://www.googleapis.com/auth/userinfo.email");

这个访问令牌我没有存储和尝试重复使用。相反,我每次都要求一个访问令牌,期待一个新的(不同的)令牌,这样我就不需要检查它是否过期等。

但是每次我要求时我都会得到相同的访问令牌。我卸载了该应用程序,清除了Google+ 应用程序的数据,但我仍然获得了相同的访问令牌。

实际问题是,使用此访问令牌会出现 401 错误 -"message": "Invalid Credentials"

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

这是浏览器上的响应。

在设备上,我在 Logcat 中得到了这个:

02-25 02:09:46.919: W/System.err(3022): java.io.FileNotFoundException: https://www.googleapis.com/oauth2/v1/userinfo
02-25 02:09:46.929: W/System.err(3022):     at org.apache.harmony.luni.internal.net.www.protocol.http.HttpURLConnectionImpl.getInputStream(HttpURLConnectionImpl.java:521)
02-25 02:09:46.929: W/System.err(3022):     at org.apache.harmony.luni.internal.net.www.protocol.https.HttpsURLConnectionImpl.getInputStream(HttpsURLConnectionImpl.java:258)
02-25 02:09:46.929: W/System.err(3022):     at com.example.gmaillogin.MainActivity$connectAsyncTask.doInBackground(MainActivity.java:269)
02-25 02:09:46.929: W/System.err(3022):     at com.example.gmaillogin.MainActivity$connectAsyncTask.doInBackground(MainActivity.java:1)
02-25 02:09:46.929: W/System.err(3022):     at android.os.AsyncTask$2.call(AsyncTask.java:185)
02-25 02:09:46.929: W/System.err(3022):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:306)
02-25 02:09:46.929: W/System.err(3022):     at java.util.concurrent.FutureTask.run(FutureTask.java:138)
02-25 02:09:46.929: W/System.err(3022):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1088)
02-25 02:09:46.929: W/System.err(3022):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:581)
02-25 02:09:46.929: W/System.err(3022):     at java.lang.Thread.run(Thread.java:1019)

第 269 行:

urlConnection = (HttpURLConnection) url.openConnection();

完整代码:

URL url = new URL("https://www.googleapis.com/oauth2/v1/userinfo");
String sAccessToken = GoogleAuthUtil.getToken(
                        MainActivity.this,
                        mPlusClient.getAccountName() + "",
                        "oauth2:" + Scopes.PLUS_PROFILE + " 
                                            https://www.googleapis.com/auth/userinfo.profile 
                                            https://www.googleapis.com/auth/userinfo.email");

            Log.d("sAccessToken = ", "" + sAccessToken);
            urlConnection = (HttpURLConnection) url.openConnection();
            urlConnection.setRequestProperty("Authorization", "Bearer "
                    + sAccessToken);

            BufferedReader r = new BufferedReader(new InputStreamReader(
                    urlConnection.getInputStream(), "UTF-8"));
            StringBuilder total = new StringBuilder();
            String line;
            while ((line = r.readLine()) != null) {
                total.append(line);
            }
            line = total.toString();

编辑:

这肯定是因为访问令牌已过期。这是意料之中的,但我想我每次打电话都会得到一个新的访问令牌。

但正如这里所说:

如果 android 设备已经有一个身份验证令牌(对于您尝试访问的特定 GData 服务),它将返回给您

所以,我必须这样做:

if (server indicates token is invalid) {
              // invalidate the token that we found is bad so that GoogleAuthUtil won't
              // return it next time (it may have cached it)
              GoogleAuthUtil.invalidateToken(Context, String)(context, token);
              // consider retrying getAndUseTokenBlocking() once more
              return;
          }

就像文档说的

但是如何检查访问令牌是否已过期或无效?

通过捕捉异常 - 是唯一的解决方案吗?

实际上例外是java.io.FileNotFoundException没有意义的。

4

2 回答 2

4

Covering the bases here: Did you register a Google APIs Console project and create a OAuth 2.0 client ID for your Android app, by specifying your app's package name and the SHA-1 fingerprint of your certificate (test or prod)?

Often the 401 invalid credentials message is due to the APIs Console project either not being configured or one of the settings being invalid.

The steps to walk through that set up process specifically for the Google+ SDK are here: https://developers.google.com/+/mobile/android/getting-started

Edit

The PlusClient can automatically handle your tokens for you. I'd suggest using the methods that the PlusClient provides and allowing the client to manage the tokens rather than doing it manually. If you need email or profile data via the PlusClient see PlusClient.loadPerson() and for email PlusClient.getAccountName(), more details at https://developers.google.com/+/mobile/android/people

于 2013-03-05T18:51:15.757 回答
0

我有类似的问题。为了解决访问令牌过期的问题,我在客户端解码令牌,并检查令牌有效负载中的“exp”字段。这样,我可以在发送到服务器之前识别令牌过期。更多细节在这篇博文中

于 2013-06-11T12:10:11.690 回答