【问题标题】:Google+ getToken() throws UserRecoverableAuthException: NeedPermissionGoogle+ getToken() 抛出 UserRecoverableAuthException:NeedPermission
【发布时间】:2015-05-12 01:48:53
【问题描述】:

我想获取授权代码来为我的应用启用服务器端 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

参数code = 4/YUVer...

该代码与我尝试通过 Unity 函数获取的代码相同吗?

提前致谢,如有任何帮助,我将不胜感激。

【问题讨论】:

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


    【解决方案1】:

    一些值得检查的事情:

    • 您的重定向 URI 是什么?

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

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

    您收到的错误表明用户在授权应用程序时单击了取消(或从未单击过确认)。如果您获得授权码(4/YUY.... 字符串),那么这应该不会发生。

    • 您交换的令牌是否正确?

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

    回到你的 cmets,这是有道理的:

    该代码与我尝试通过 Unity 函数获取的代码相同吗?

    您在 OAuth 服务器重定向后获得的代码是您想要的代码,它是从 Android 的 getToken 中返回的。有关获取/交换代码的更多信息,请查看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;
    }
    

    【讨论】:

    • 感谢您的回复。首先是 URI:在 Android 应用程序的开发者控制台上,它具有以下值:urn:ietf:wg:oauth:2.0:oob http://localhost。我应该使用来自 Android 应用程序还是 Web 应用程序的客户端 ID?第二件事:没有取消,通过 Unity 插件登录后,我调用我的方法 GetToken()。我试图从这个方法中得到那个代码(4/YUV)。在“或者也许你可以澄清......”之后的问题中,我的意思是 URL 返回的代码与我试图通过脚本获取的代码相同。我不需要访问令牌、刷新令牌等令牌,只需要授权码。谢谢你的链接,我去看看。
    • 添加更多示例。
    • 好吧,这可能是我的解决方案,处理 UserRecoverableAuthException 。我编写了自己的插件来获取令牌,但是在授予离线访问权限时,应用程序崩溃了。如果可以,请查看我的问题:issue
    【解决方案2】:

    我遇到了同样的问题。我就是这样解决的。

    第 1 步:我在 Try Sign-In for Android 上关注了 Google 文档。所以我有登录工作。我必须按照本教程Start Integrating Google Sign-In into Your Android App 创建“Android 客户端 ID”

    第 2 步: 同样,在创建“Android 客户端 ID”的同时,我必须创建“Web 客户端 ID”。这一步为我提供了“Web 的客户端 ID”,稍后我将使用它。

    第 3 步:

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

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

    您可以按照教程找到GetIdTokenTask类“ 使用后端服务器进行身份验证”。这是 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
                // ...
            }
        }
    
    }
    

    【讨论】:

      猜你喜欢
      • 2021-12-23
      • 1970-01-01
      • 2019-08-18
      • 1970-01-01
      • 1970-01-01
      • 2016-10-16
      • 2012-09-01
      • 2017-12-30
      • 1970-01-01
      相关资源
      最近更新 更多