从 GoogleAuthUtil 和 Plus.API 迁移

如果您过去使用 GoogleAuthUtil.getTokenPlus.API 与 Google Sign-In 集成,则应迁移到最新的 Sign-In API,以提高安全性并改善用户体验。

从访问令牌反模式迁移

您不应将通过 GoogleAuthUtil.getToken 获取的访问令牌作为身份断言发送到后端服务器,因为您无法轻松验证令牌是否已发送到您的后端,因此很容易从攻击者插入访问令牌。

例如,如果您的 Android 代码如下例所示,则您应该将您的应用迁移到当前的最佳实践。

Android 代码

在此示例中,访问令牌请求使用 oauth2: 和范围字符串作为 GoogleAuthUtil.getToken 调用 (oauth2:https://www.googleapis.com/auth/plus.login) 的 scope 参数。

请改用 ID 令牌流程或授权代码流程,而不是使用通过 GoogleAuthUtil.getToken 获取的访问令牌进行身份验证。

迁移到 ID 令牌流程

如果您只需要用户的 ID、电子邮件地址、姓名或个人资料照片网址,请使用 ID 令牌流程

如需迁移到 ID 令牌流程,请进行以下更改:

Android 客户端

  • 移除 GET_ACCOUNTS(通讯录)权限(如果您提出要求)
  • 将使用 GoogleAuthUtilPlus.APIAccountPicker.newChooseAccountIntent()AccountManager.newChooseAccountIntent() 的任何代码切换为使用 GoogleSignInOptions.Builder.requestIdToken(...) 配置的 Auth.GOOGLE_SIGN_IN_API

服务器端

迁移到服务器授权代码流程

如果您的服务器需要访问其他 Google API(例如 Google 云端硬盘、YouTube 或通讯录),请使用服务器身份验证代码流程

如需迁移到服务器授权代码流程,请进行以下更改:

Android 客户端

  • 应请求移除 GET_ACCOUNTS(通讯录)权限
  • 将使用 GoogleAuthUtilPlus.APIAccountPicker.newChooseAccountIntent()AccountManager.newChooseAccountIntent() 的任何代码切换为使用 GoogleSignInOptions.Builder.requestServerAuthCode(...) 配置的 Auth.GOOGLE_SIGN_IN_API

服务器端

您仍然可以在旧端点和新端点之间共享 API 访问逻辑。例如:

GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(...);
String accessToken = tokenResponse.getAccessToken();
String refreshToken = tokenResponse.getRefreshToken();
Long expiresInSeconds = tokenResponse.getExpiresInSeconds();

// Shared by your old and new implementation, old endpoint can pass null for refreshToken
private void driveAccess(String refreshToken, String accessToken, Long expiresInSeconds) {
   GoogleCredential credential = new GoogleCredential.Builder()
           .setTransPort(...)
           ...
           .build();
   credential.setAccessToken(accessToken);
   credential.setExpiresInSeconds(expiresInSeconds);
   credential.setRefreshToken(refreshToken);
}

从 GoogleAuthUtil ID 令牌流程迁移

如果您使用 GoogleAuthUtil 获取 ID 令牌,则应迁移到新的 Sign-In API ID 令牌流程

例如,如果您的 Android 代码如下例所示,您应进行迁移:

Android 代码

在此示例中,ID 令牌请求使用 audience:server:client_id 以及您的网站服务器的客户端 ID 作为 GoogleAuthUtil.getToken 调用 (audience:server:client_id:9414861317621.apps.googleusercontent.com) 的“scope”(范围)参数。

新的 Sign-In API ID 令牌流程具有以下优势:

  • 简化了一键登录体验
  • 您的服务器无需额外的网络调用即可获取用户个人资料信息

如需迁移到 ID 令牌流程,请进行以下更改:

Android 客户端

  • 移除 GET_ACCOUNTS(通讯录)权限(如果您提出要求)
  • 将使用 GoogleAuthUtilPlus.APIAccountPicker.newChooseAccountIntent()AccountManager.newChooseAccountIntent() 的任何代码切换为使用 GoogleSignInOptions.Builder.requestIdToken(...) 配置的 Auth.GOOGLE_SIGN_IN_API

服务器端

与使用已废弃格式的 GoogleAuthUtil.getToken 不同,新的 Sign-In API 会颁发符合 OpenID Connect 规范的 ID 令牌。具体而言,发行者现在是 https://accounts.google.com,采用 https 架构。

在迁移过程中,您的服务器需要验证旧版和新版 Android 客户端中的 ID 令牌。如需验证令牌的两种格式,请进行与您使用的客户端库(如果有)对应的更改:

  • Java(Google API 客户端库):升级到 1.21.0 或更高版本
  • PHP(Google API 客户端库):如果您使用 v1,请升级到 1.1.6 或更高版本;如果您使用 v2,请升级到 2.0.0-RC1 或更高版本
  • Node.js:升级到 0.9.7 或更高版本
  • Python 或您自己的实现:接受以下两个签发者:https://accounts.google.comaccounts.google.com

从 GoogleAuthUtil 服务器授权代码流程迁移

如果您使用 GoogleAuthUtil 获取服务器授权代码,则应迁移到新的 Sign-In API 授权代码流程

例如,如果您的 Android 代码如以下示例所示,则应进行迁移:

Android 代码

在该示例中,服务器授权代码请求使用 oauth2:server:client_id + 您的 Web 服务器的客户端 ID 作为 GoogleAuthUtil.getToken 调用 (oauth2:server:client_id:9414861317621.apps.googleusercontent.com) 的 scope 参数。

新的 Sign-In API 身份验证代码流程具有以下优势:

  • 简化了一键登录体验
  • 如果您按照以下迁移指南操作,您的服务器在进行身份验证码交换时可以获取包含用户个人资料信息的 ID 令牌

如需迁移到新的身份验证码流程,请进行以下更改:

Android 客户端

  • 应请求移除 GET_ACCOUNTS(通讯录)权限
  • 将使用 GoogleAuthUtilPlus.APIAccountPicker.newChooseAccountIntent()AccountManager.newChooseAccountIntent() 的任何代码切换为使用 GoogleSignInOptions.Builder.requestServerAuthCode(...) 配置的 Auth.GOOGLE_SIGN_IN_API

服务器端

保留当前代码,但在构建 GoogleAuthorizationCodeTokenRequest 对象时将 https://oauth2.googleapis.com/token 指定为令牌服务器端点,以便您可以获取包含用户电子邮件地址、用户 ID 和个人资料信息的 ID 令牌,而无需进行其他网络调用。此端点完全向后兼容,并且以下代码适用于从新旧 Android 客户端实现中检索的服务器身份验证代码。

GoogleTokenResponse tokenResponse = new GoogleAuthorizationCodeTokenRequest(
                transport,
                jsonFactory,
                // Use below for tokenServerEncodedUrl parameter
                "https://oauth2.googleapis.com/token",
                clientSecrets.getDetails().getClientId(),
                clientSecrets.getDetails().getClientSecret(),
                authCode,
                REDIRECT_URI)
               .execute();

...

// You can also get an ID token from auth code exchange.
GoogleIdToken googleIdToken = tokenResponse.parseIdToken();
GoogleIdTokenVerifier verifier = new GoogleIdTokenVerifier.Builder(transport, jsonFactory)
        .setAudience(Arrays.asList(SERVER_CLIENT_ID))
        .setIssuer("https://accounts.google.com")
        .build();
// Refer to ID token documentation to see how to get data from idToken object.
GoogleIdToken idToken = verifier.verify(idTokenString);
...