33

我尝试按照教程:https ://developers.google.com/android/guides/http-auth 。

代码:

token = GoogleAuthUtil.getToken(getApplicationContext(),
                        mEmail, mScope);

显现:

<uses-permission android:name="android.permission.GET_ACCOUNTS"/>
<uses-permission android:name="android.permission.NETWORK"/>
<uses-permission android:name="android.permission.USE_CREDENTIALS"/>
<uses-permission android:name="android.permission.INTERNET"/>

错误:

01-17 18:37:38.230: W/System.err(3689): com.google.android.gms.auth.UserRecoverableAuthException: NeedPermission
01-17 18:37:38.230: W/System.err(3689):     at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
01-17 18:37:38.230: W/System.err(3689):     at com.google.android.gms.auth.GoogleAuthUtil.getToken(Unknown Source)
01-17 18:37:38.230: W/System.err(3689):     at com.example.mgoogleauth.MainActivity$GetIOStreamTask.doInBackground(MainActivity.java:39)
01-17 18:37:38.230: W/System.err(3689):     at com.example.mgoogleauth.MainActivity$GetIOStreamTask.doInBackground(MainActivity.java:1)
01-17 18:37:38.230: W/System.err(3689):     at android.os.AsyncTask$2.call(AsyncTask.java:287)
01-17 18:37:38.230: W/System.err(3689):     at java.util.concurrent.FutureTask$Sync.innerRun(FutureTask.java:305)
01-17 18:37:38.230: W/System.err(3689):     at java.util.concurrent.FutureTask.run(FutureTask.java:137)
01-17 18:37:38.230: W/System.err(3689):     at java.util.concurrent.ThreadPoolExecutor.runWorker(ThreadPoolExecutor.java:1076)
01-17 18:37:38.230: W/System.err(3689):     at java.util.concurrent.ThreadPoolExecutor$Worker.run(ThreadPoolExecutor.java:569)
01-17 18:37:38.230: W/System.err(3689):     at java.lang.Thread.run(Thread.java:856)
4

6 回答 6

75

尝试遵循适用于 Android 的 Drive 快速入门,这是一个分步指南,展示了如何授权和上传文件到 Drive:https ://developers.google.com/drive/quickstart-android

更具体地说,您似乎没有捕获 UserRecoverableException 并触发意图让用户授权应用程序。这记录在您在快速入门示例中链接和处理的 Google Play 服务文档中,如下所示:

...
} catch (UserRecoverableAuthIOException e) {
  startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
}
... 
于 2013-01-17T19:05:14.290 回答
12

官方 GoogleAuthUtil 教程的 getAndUseAuthTokenBlocking() 方法很好地解释了如何处理异常:

// Example of how to use the GoogleAuthUtil in a blocking, non-main thread context
   void getAndUseAuthTokenBlocking() {
       try {
          // Retrieve a token for the given account and scope. It will always return either
          // a non-empty String or throw an exception.
          final String token = GoogleAuthUtil.getToken(Context, String, String)(context, email, scope);
          // Do work with token.
          ...
          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;
          }
          return;
       } catch (GooglePlayServicesAvailabilityException playEx) {
         Dialog alert = GooglePlayServicesUtil.getErrorDialog(
             playEx.getConnectionStatusCode(),
             this,
             MY_ACTIVITYS_AUTH_REQUEST_CODE);
         ...
       } catch (UserRecoverableAuthException userAuthEx) {
          // Start the user recoverable action using the intent returned by
          // getIntent()
          myActivity.startActivityForResult(
                  userAuthEx.getIntent(),
                  MY_ACTIVITYS_AUTH_REQUEST_CODE);
          return;
       } catch (IOException transientEx) {
          // network or server error, the call is expected to succeed if you try again later.
          // Don't attempt to call again immediately - the request is likely to
          // fail, you'll hit quotas or back-off.
          ...
          return;
       } catch (GoogleAuthException authEx) {
          // Failure. The call is not expected to ever succeed so it should not be
          // retried.
          ...
          return;
       }
   }
于 2013-04-29T19:41:25.813 回答
7

我有同样的错误,在我的情况下,我使用了错误的范围,我只是改变

https://www.googleapis.com/auth/plus.login

为了

https://www.googleapis.com/auth/userinfo.profile
于 2014-11-10T20:27:36.257 回答
3

在此文档页面 https://developers.google.com/+/mobile/android/sign-in上,该示例对此异常有很好的解释。

特别是,看起来应该注意这一行:

请求授权代码将始终在第一次调用 GoogleAuthUtil.getToken 时抛出 UserRecoverableAuthException

catch (UserRecoverableAuthException e) {
  // Requesting an authorization code will always throw
  // UserRecoverableAuthException on the first call to GoogleAuthUtil.getToken
  // because the user must consent to offline access to their data.  After
  // consent is granted control is returned to your activity in onActivityResult
  // and the second call to GoogleAuthUtil.getToken will succeed.
  startActivityForResult(e.getIntent(), AUTH_CODE_REQUEST_CODE);
  return;
}
于 2015-04-22T18:13:46.790 回答
2

我发现这里的答案是被动的解决方案,而不是预防性的。
根据我很短的经验,UserRecoverableAuthException: NeedPermission 会在以下3种情况下抛出:

#1 登录 Google 时未请求适当的范围

检查您请求的范围是否正确。Android 应该通过权限请求对话框要求用户在身份验证过程之后允许权限。这将在调用 API 时防止 UserRecoverableAuthException。

GoogleSignInOptions o = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
            .requestScopes(new Scope(DriveScopes.DRIVE)) // request permission for Drive API
            .requestScopes(new Scope(SheetsScopes.SPREADSHEETS)) // request permission for Sheets API
            .requestEmail()
            .build();

#2 用户拒绝了权限

用户在权限请求对话框上按下了“拒绝”按钮。

#3 用户拒绝了您应用的权限

对于 Android 8.1.x,有一个菜单,您可以在其中拒绝个别应用程序的权限。不过,不确定其他版本。

Settings > Google > Connected apps

#2 和 #3 抛出的 UserRecoverableAuthException 是不可避免的,因为它们是用户活动的结果。但是,尽管用户拒绝了,但用下面的代码再次显示权限请求对话框不是没有意义吗?

} catch (UserRecoverableAuthIOException e) {
  startActivityForResult(e.getIntent(), REQUEST_AUTHORIZATION);
}
于 2019-01-15T08:20:48.080 回答
1

文档最近已更新,现在支持 SDK M(请求权限)并显示 OAuth 对话框。

注意 Google Docs 通常不是最新的,但在您报告问题时它们似乎会引起注意。该示例已更新,我在一周内发送了反馈。因此,如果您看到无效的示例,请发送反馈!

https://developers.google.com/drive/v3/web/quickstart/android

于 2016-04-06T19:22:26.133 回答