android - Google 登录服务器实现返回 401

标签 android google-play-services google-signin googlesigninaccount

尝试从 Play Services 8.1 中的 Google+ 登录切换到 Play Services 8.3 中的新 Google 登录时,服务器端组件停止工作,并开始在每次对 Google 服务器的 API 调用时抛出 401 错误。

当 Android 应用使用 Google Play Services 8.1 时:

build.gradle:

compile 'com.google.android.gms:play-services-plus:8.1.0'

Android 客户端:

mGoogleApiClient = new GoogleApiClient.Builder(this)
         .addApi(Plus.API)
         .addScope(Plus.SCOPE_PLUS_PROFILE)
         .addScope(new Scope("email"))
         .build();
String scopes = "oauth2:profile email";    
accessToken = GoogleAuthUtil.getToken(
        SignInActivity.this, 
        Plus.AccountApi.getAccountName(mGoogleApiClient), 
        scopes); // then send accessToken to the server

服务器端:

 // get user details from Google+ REST API
 GoogleCredential credential = new GoogleCredential().setAccessToken(accessToken);
 Plus plusService = new Plus.Builder(new NetHttpTransport(), new JacksonFactory(), null)
         .setApplicationName("AppName")
         .setHttpRequestInitializer(credential)
         .build();
 Person person = plusService.people().get("me").execute();

切换到 Google Play 服务 8.3 时:

build.gradle:

 compile 'com.google.android.gms:play-services-auth:8.3.0'

Android 应用:

GoogleSignInOptions googleSignInOptions = new GoogleSignInOptions.Builder(GoogleSignInOptions.DEFAULT_SIGN_IN)
        .requestServerAuthCode("GOOGLE_CLIENT_ID", false)
        .requestEmail()
        .build();
 mGoogleApiClient = new GoogleApiClient.Builder(this)
         .addApi(Auth.GOOGLE_SIGN_IN_API, googleSignInOptions)
         .build();

使用相同的服务器代码,get("me") 调用返回:

com.google.api.client.googleapis.json.GoogleJsonResponseException: 401 Unauthorized
{
  "code" : 401,
  "errors" : [ {
    "domain" : "global",
    "location" : "Authorization",
    "locationType" : "header",
    "message" : "Invalid Credentials",
    "reason" : "authError"
  } ],
  "message" : "Invalid Credentials"
}

最佳答案

另请注意,使用新的 Google Sign-In Api,只要在 Android 客户端上请求基本配置文件范围,您就可以在服务器上将代码交换为 token 时获得 ID token 。如果您要查找的只是全名、电子邮件地址和图片,那就足够了。

您将传递 GoogleSignInAccount.getServerAuthCode() 的结果到您的服务器,然后使用如下代码:

HttpTransport transport = new NetHttpTransport();
JacksonFactory jsonFactory = new JacksonFactory();

try {
  // Exchanges the code for tokens.
  GoogleTokenResponse response = new GoogleAuthorizationCodeTokenRequest(
      transport,
      jsonFactory,
      // Very important: Explicitly specify this new endpoint.
      "https://www.googleapis.com/oauth2/v4/token",
      SERVER_CLIENT_ID,
      SERVER_CLIENT_SECRET,
      serverAuthCodeFromAndroid,
      "" /* redirectUri, must be blank with auth code coming from Android */)
    .execute();

  // Get the id token from the exchange result
  // It will be non-null if basic profile scopes are requested 
  // when requesting the serverAuthCode on (Android) client side.
  GoogleIdToken googleIdToken = response.parseIdToken();

  // Verify the id token
  GoogleIdTokenVerifier verifier =
          new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
              // For some old version of libraries
              .setIssuer("https://accounts.google.com")
              .setAudience(Arrays.asList(SERVER_CLIENT_ID))
              .build();
  boolean verified = googleIdToken.verify(verifier);
  if (!verified) {
    // Spoofing!! This is not a legitimate id token issued by 
    // Google to your web application!
    return;
  }

  // Get the profile info.
  GoogleIdToken.Payload payload = googleIdToken.getPayload();
  String userId = payload.getSubject();
  String email = payload.getEmail();
  boolean emailVerified = Boolean.valueOf(payload.getEmailVerified());
  String name = (String) payload.get("name");
  String pictureUrl = (String) payload.get("picture");
  String locale = (String) payload.get("locale");
  String familyName = (String) payload.get("family_name");
  String givenName = (String) payload.get("given_name");
} catch (GeneralSecurityException | IOException e) {
  // error handling
}

无需 Google+ API!

关于android - Google 登录服务器实现返回 401,我们在Stack Overflow上找到一个类似的问题: https://stackoverflow.com/questions/33574018/

相关文章:

android - Instant app 在 adview.loadAd 上崩溃,SecurityException : Failed to find provider com. google.android.gsf.gservices

android - 更新Google play服务到8.4.0推送通知后自己显示

c# - 使用 Azure 移动服务对现有 Windows 10 UWP 应用程序进行 Google 身份验证

android - 将recyclerview的滚动条放在父布局android的末尾

in-app-purchase - Google Play 结算 : Error retrieving information from server. [DF-PPA-10]

java - 如何正确获取HTML Asset

swift - 如何使用 Kitura 服务器连接和授权 google auth iOS 客户端?

ios - 无法让 google 登录来处理 URL

java - 应用程序无法启动,立即强制停止(代码如下)

java - Android java解析Json从url到对象列表