谷歌+安卓版:无效的凭据

8
我正在使用以下代码获取Access Token,在连接到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”:“无效凭据”。
{
 "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,这没有意义。


你手动尝试这样做而不使用PlusClient提供的方法,是否有原因?客户端应自动代表您的应用程序处理令牌交换。 - BrettJ
我按照这个链接获取了访问令牌。还有其他自动处理的方式吗? - Archie.bpgc
2个回答

4
在这里涵盖基础知识:您是否注册了Google APIs控制台项目并为您的Android应用程序创建了OAuth 2.0客户端ID,通过指定您的应用程序的包名称和证书(测试或生产)的SHA-1指纹?通常,401无效凭据消息是由于APIs控制台项目未配置或其中一个设置无效而导致的。有关专门为Google+ SDK设置过程的步骤在此处:https://developers.google.com/+/mobile/android/getting-started 编辑 PlusClient可以自动处理您的令牌。我建议使用PlusClient提供的方法,并允许客户端管理令牌,而不是手动处理。如果您需要通过PlusClient获取电子邮件或个人资料数据,请参见PlusClient.loadPerson()和电子邮件PlusClient.getAccountName(),更多详细信息请参见https://developers.google.com/+/mobile/android/people

1
是的,我按照你在答案中提到的所有步骤都做了。经过一些研究,我发现问题肯定是由于“访问令牌”引起的。有没有办法检查访问令牌是否过期或有效? - Archie.bpgc
请查看快速入门示例,了解如何验证令牌以确保它们不仅有效,而且对于此特定用户和应用程序也是有效的。Java 服务器端应用程序验证可以在第140行开始查看:https://github.com/googleplus/gplus-quickstart-java/blob/master/src/com/google/plus/samples/quickstart/Signin.java#L141 - BrettJ
嘿@BrettJ,这个以前对我有用,但是几天前它停止工作了,现在它抛出了这个错误com.google.android.gms.auth.GoogleAuthException: Unknown。你知道为什么吗?我的scopes有问题吗?https://gist.github.com/lawloretienne/7351151 - Etienne Lawlor
你最近升级了SDK和Google Play服务吗? - BrettJ

0

我曾经遇到过类似的问题。为了解决Access Token过期的问题,我在客户端对Token进行解码,并检查Token负载中的“exp”字段。通过这种方式,我可以在将Token发送到服务器之前识别Token是否已过期。 更多细节请参考博客文章


网页内容由stack overflow 提供, 点击上面的
可以查看英文原文,
原文链接