Google+ getToken() 抛出 UserRecoverableAuthException: NeedPermission
Google+ getToken() throws UserRecoverableAuthException: NeedPermission
我想获取授权码,以便为我的应用程序启用服务器端 API 访问权限。我在 Unity3D 中使用 google Play games services plugin for Unity 执行此过程。我有从 GoogleAuthUtils class:
调用本机 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"
和 returns 观众令牌。
我不认为我做错了什么。
有什么建议吗?
或者您可以澄清一下,那是使用 URL 调用:
将我重定向到 url 喜欢
参数代码 = 4/YUVer...
该代码是否与我尝试通过 Unity 功能获得的代码相同?
提前致谢,如有任何帮助,我将不胜感激。
一些值得检查的事情:
- 您的重定向 URI 是什么?
当您从 Android 发出请求时,您的重定向 URI 将是特定于设备的重定向 URI,urn:ietf:wg:oauth:2.0:oob.
- 您(或您的用户)要取消授权步骤吗?
您收到的错误表明用户在授权应用程序时点击了取消(或从未点击过确认)。如果您获得了授权代码(4/YUY.... 字符串),则不应发生这种情况。
- 您交换的代币是正确的代币吗?
authZ、访问令牌、刷新令牌和授权代码有 3 种重要的 OAuth 响应类型。如果您正在尝试交换访问令牌(或刷新令牌)作为授权代码,则响应将没有任何意义。确保您使用的是来自 getToken 的授权代码,并在执行令牌交换时传递正确匹配的重定向 URI。
回到你的评论,这是有道理的:
is that code the SAME one as that I am trying to get via Unity function?
您在 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 步: 我按照 Try Sign-In for Android. So I had Sign-In working. I had to follow this tutorial Start Integrating Google Sign-In into Your Android App 的 Google 文档创建了 "Client ID for Android"
第 2 步:
同样,在我创建"Client ID for Android"的同时,我不得不创建"Client ID for Web"。这一步给了我 "Client ID for Web",我稍后会用到它。
第 3 步:
按照本教程获取令牌 ID "Authenticate with a backend server"。在登录时的 onConnected 方法中,添加
GetIdTokenTask getIdTokenTask = new GetIdTokenTask();
getIdTokenTask.execute();
您可以按照教程找到 GetIdTokenTask class
使用后端服务器进行身份验证”。这是 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 步: 配置 SERVER_CLIENT_ID 我们可以从 GetIdTokenTask class[中的第 2 步获得=14=]
这里有一个 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
// ...
}
}
}
我想获取授权码,以便为我的应用程序启用服务器端 API 访问权限。我在 Unity3D 中使用 google Play games services plugin for Unity 执行此过程。我有从 GoogleAuthUtils class:
调用本机 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"
和 returns 观众令牌。
我不认为我做错了什么。
有什么建议吗?
或者您可以澄清一下,那是使用 URL 调用:
将我重定向到 url 喜欢
参数代码 = 4/YUVer...
该代码是否与我尝试通过 Unity 功能获得的代码相同?
提前致谢,如有任何帮助,我将不胜感激。
一些值得检查的事情:
- 您的重定向 URI 是什么?
当您从 Android 发出请求时,您的重定向 URI 将是特定于设备的重定向 URI,urn:ietf:wg:oauth:2.0:oob.
- 您(或您的用户)要取消授权步骤吗?
您收到的错误表明用户在授权应用程序时点击了取消(或从未点击过确认)。如果您获得了授权代码(4/YUY.... 字符串),则不应发生这种情况。
- 您交换的代币是正确的代币吗?
authZ、访问令牌、刷新令牌和授权代码有 3 种重要的 OAuth 响应类型。如果您正在尝试交换访问令牌(或刷新令牌)作为授权代码,则响应将没有任何意义。确保您使用的是来自 getToken 的授权代码,并在执行令牌交换时传递正确匹配的重定向 URI。
回到你的评论,这是有道理的:
is that code the SAME one as that I am trying to get via Unity function?
您在 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 步: 我按照 Try Sign-In for Android. So I had Sign-In working. I had to follow this tutorial Start Integrating Google Sign-In into Your Android App 的 Google 文档创建了 "Client ID for Android"
第 2 步: 同样,在我创建"Client ID for Android"的同时,我不得不创建"Client ID for Web"。这一步给了我 "Client ID for Web",我稍后会用到它。
第 3 步:
按照本教程获取令牌 ID "Authenticate with a backend server"。在登录时的 onConnected 方法中,添加
GetIdTokenTask getIdTokenTask = new GetIdTokenTask();
getIdTokenTask.execute();
您可以按照教程找到 GetIdTokenTask class 使用后端服务器进行身份验证”。这是 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 步: 配置 SERVER_CLIENT_ID 我们可以从 GetIdTokenTask class[中的第 2 步获得=14=]
这里有一个 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
// ...
}
}
}