Google+ getToken()会抛出UserRecoverableAuthException:NeedPermission

时间:2015-03-10 14:49:53

标签: android unity3d oauth-2.0 google-plus token

我想获取授权码,以便为我的应用启用服务器端API访问。我在Unity3D中使用针对Unity的Google Play游戏服务插件执行此过程。我有从GoogleAuthUtils类调用本机getToken()函数的函数:

 public string GetToken() {
            string token = null;
            Debug.Log("Before RetrieveUserEmail");
            string email = RetrieveUserEmail() ?? "NULL";
            Debug.Log("After RetrieveUserEmail email: " + email);
            string scope = "oauth2:server:client_id:" + "666666666666-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.apps.googleusercontent.com"
                + ":api_scope:" + "https://www.googleapis.com/auth/plus.login";
            using (AndroidJavaClass jc_unityPlayer = new AndroidJavaClass("com.unity3d.player.UnityPlayer"),
                jc_gau = new AndroidJavaClass("com.google.android.gms.auth.GoogleAuthUtil")) {
                using(AndroidJavaObject jo_Activity = jc_unityPlayer.GetStatic<AndroidJavaObject>("currentActivity")) {
                    token = jc_gau.CallStatic<string>("getToken", jo_Activity, email, scope);
                }
            }
            Debug.Log("Token " + token);
            return token;
        }

但是我得到了AndroidJavaException:com.google.android.gms.auth.UserRecoverableAuthException:NeedPermission

此功能接合正常,因为它适用于

string scope = "audience:server:client_id:" + "666666666666-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.apps.googleusercontent.com"

并返回受众标记。

我无法想象我做错了什么。

有什么建议吗?

或者你可以澄清一下,即使用URL调用:

https://accounts.google.com/o/oauth2/auth?scope=https://www.googleapis.com/auth/plus.login&client_id=666666666666-aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaa.apps.googleusercontent.com&response_type=code&redirect_uri=http://someurl.com/oauth2callback

将我重定向到像

这样的网址

http://someurl.com/oauth2callback?code=4/YUVerNRxRQ8_XHPJ4USfjhYLCZ-fKoQyD1v5H_cZH_o.IvzKlyDEVOcVrjMoGjtSfTpyjkcImAI&authuser=0&num_sessions=1&session_state=14ac991a51396ecb690abac27e676846c7a8297e..c560&prompt=none

参数代码= 4 / YUVer ...

是那个代码是我试图通过Unity函数得到的那个代码吗?

提前感谢,我将不胜感激。

2 个答案:

答案 0 :(得分:0)

一些值得检查的事情:

  • 您的重定向URI是什么?

当您从Android发出请求时,您的重定向URI将是特定于设备的重定向URI,urn:ietf:wg:oauth:2.0:oob。

  • 您(或您的用户)是否取消了授权步骤?

您获得的错误表示用户在授权应用时点击取消(或从未点击确认)。如果您正在获取授权代码(4 / YUY ....字符串),那么这不应该发生。

  • 您正在交换正确令牌的令牌吗?

authZ,访问令牌,刷新令牌和授权代码有三种重要的OAuth响应类型。如果您尝试将访问令牌(或刷新令牌)作为授权代码进行交换,则响应将没有任何意义。确保您使用getToken中的授权代码,并在执行令牌交换时传递正确匹配的重定向URI。

回到你的评论,这是有道理的:

  

是那个代码是我试图通过Unity函数得到的那个代码吗?

OAuth服务器重定向后获得的代码是您想要的代码,它是从getToken中的Android返回的。有关获取/交换代码的更多信息,请查看Google+ Android Client & Server Sign-In上的博客文章。

有关如何获取代码的演示,请参阅Haiku+ Android client。相关代码是:

public String getCodeSynchronous() throws GoogleAuthException, CodeException {
    StringBuilder scopeString = new StringBuilder("");
    for (String scope : Constants.SCOPES) {
        scopeString.append(" ").append(scope);
    }
    String scope = new StringBuilder("oauth2:server:client_id:")
            .append(Constants.SERVER_CLIENT_ID)
            .append(":api_scope:")
            .append(scopeString.toString())
            .toString();
    Bundle appActivities = new Bundle();
    String types = TextUtils.join(" ", Constants.ACTIONS);
    appActivities.putString(GoogleAuthUtil.KEY_REQUEST_VISIBLE_ACTIVITIES, types);

    String code = null;
    try {
        code = GoogleAuthUtil.getToken(
                mContext,
                mAccountName,
                scope,
                appActivities);
        // Immediately invalidate so we get a different one if we have to try again.
        GoogleAuthUtil.invalidateToken(mContext, code);
    } catch (IOException e) {
        Log.e(TAG, e.getMessage(), e);
        throw new CodeException("Error: could not establish connection to server.");
    }

    return code;
}

有关如何更换代码服务器端,请参阅Haiku+ Java server

try {
  // Upgrade the authorization code into an access and refresh token.
  return new GoogleAuthorizationCodeTokenRequest(HaikuPlus.TRANSPORT,
    HaikuPlus.JSON_FACTORY,
    getClientId(),
    getClientSecret(),
    authorization,
    redirectUri).execute();

} catch (TokenResponseException e) {
  //Failed to exchange authorization code.
  logger.log(Level.INFO, "Failed to exchange auth code; return 400", e);
  response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  return null;
} catch (IOException e) {
  logger.log(Level.INFO, "Failed to exchange auth code; return 400", e);
  response.setStatus(HttpServletResponse.SC_BAD_REQUEST);
  return null;
}

答案 1 :(得分:0)

我有同样的问题。这就是我解决它的方式。

第1步:我在Try Sign-In for Android跟踪了Google文档。所以我有登录工作。我必须按照本教程Start Integrating Google Sign-In into Your Android App创建&#34; Android的客户端ID&#34;

第2步: 同样,在我为Android&#34;创建&#34;客户端ID的同时,我必须为Web&#34;创建&#34;客户端ID。这一步给了我&#34; Web的客户端ID&#34;我稍后会用。

第3步:

按照本教程获取令牌ID&#34;使用后端服务器进行身份验证&#34;。在登录时onConnected方法中,添加

GetIdTokenTask getIdTokenTask = new GetIdTokenTask();
getIdTokenTask.execute();

您可以按照教程&#34;找到GetIdTokenTask课程。 使用后端服务器进行身份验证&#34; 。以下是onConnected方法的示例。

@Override
public void onConnected(Bundle bundle) {
    // onConnected indicates that an account was selected on the device, that the selected
    // account has granted any requested permissions to our app and that we were able to
    // establish a service connection to Google Play services.
    Log.d(TAG, "onConnected:" + bundle);
    mShouldResolve = false;

    if (Plus.PeopleApi.getCurrentPerson(mGoogleApiClient) != null) {
        Person currentPerson = Plus.PeopleApi.getCurrentPerson(mGoogleApiClient);

        Log.d(TAG, "onConnected:" + "start GetIdTokenTask");

        GetIdTokenTask getIdTokenTask = new GetIdTokenTask();
        getIdTokenTask.execute();
    } else {
        Log.d(TAG, "onConnected:" + "Cannot get current person's information.");
    }
    // Show the signed-in UI
    showSignedInUI();
}

第4步:配置我们可以从 GetIdTokenTask

中的第2步获得的SERVER_CLIENT_ID

以下是GetIdTokenTask的示例。

private class GetIdTokenTask extends AsyncTask<Void, Void, String> {

    @Override
    protected String doInBackground(Void... params) {
        String accountName = Plus.AccountApi.getAccountName(mGoogleApiClient);
        Account account = new Account(accountName, GoogleAuthUtil.GOOGLE_ACCOUNT_TYPE);
        String scopes = "audience:server:client_id:" + SERVER_CLIENT_ID; // Not the app's client ID.
        try {
            return GoogleAuthUtil.getToken(getApplicationContext(), account, scopes);
        } catch (IOException e) {
            Log.e(TAG, "Error retrieving ID token.", e);
            return null;
        } catch (GoogleAuthException e) {
            Log.e(TAG, "Error retrieving ID token.", e);
            return null;
        }
    }

    @Override
    protected void onPostExecute(String result) {
        Log.i(TAG, "ID token: " + result);
        if (result != null) {
            // Successfully retrieved ID Token
            // ...
        } else {
            // There was some error getting the ID Token
            // ...
        }
    }

}