如果您过去使用 GoogleAuthUtil.getToken
或 Plus.API
集成了 Google 登录功能,则应迁移到最新的 Sign-In API,以便提升安全性和改善用户体验。
从访问令牌反模式迁移
您不应将通过 GoogleAuthUtil.getToken
获取的访问令牌作为身份断言发送到后端服务器,因为您无法轻松验证该令牌是否已签发至您的后端,从而使您容易被攻击者插入访问令牌。
例如,如果您的 Android 代码与以下示例类似,则您应将您的应用迁移到当前最佳实践。
在此示例中,访问令牌请求使用 oauth2:
和范围字符串作为 GoogleAuthUtil.getToken
调用 (oauth2:https://www.googleapis.com/auth/plus.login
) 的 scope
参数。
请使用 ID 令牌流程或身份验证代码流程,而不是使用通过 GoogleAuthUtil.getToken
获取的访问令牌进行身份验证。
迁移到 ID 令牌流程
如果您只需要用户的 ID、电子邮件地址、姓名或个人资料照片网址,请使用 ID 令牌流程。
如需迁移到 ID 令牌流程,请进行以下更改:
Android 客户端
- 如果您请求
GET_ACCOUNTS
(通讯录)权限,请将其移除 - 通过
GoogleSignInOptions.Builder.requestIdToken(...)
配置,将使用GoogleAuthUtil
、Plus.API
、AccountPicker.newChooseAccountIntent()
或AccountManager.newChooseAccountIntent()
的任何代码切换为Auth.GOOGLE_SIGN_IN_API
。
服务器端
- 为 ID 令牌身份验证创建新端点
- 迁移客户端应用后停用旧端点
迁移到服务器授权代码流程
如果您的服务器需要访问其他 Google API(例如 Google 云端硬盘、YouTube 或通讯录),请使用服务器身份验证代码流程。
如需迁移到服务器授权代码流程,请进行以下更改:
Android 客户端
- 如果您请求
GET_ACCOUNTS
(通讯录)权限,请将其移除 - 通过
GoogleSignInOptions.Builder.requestServerAuthCode(...)
配置,将使用GoogleAuthUtil
、Plus.API
、AccountPicker.newChooseAccountIntent()
或AccountManager.newChooseAccountIntent()
的任何代码切换为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 代码如以下示例所示,则应进行迁移:
在此示例中,ID 令牌请求使用 audience:server:client_id
外加您的 Web 服务器的客户端 ID 作为 GoogleAuthUtil.getToken
调用 (audience:server:client_id:9414861317621.apps.googleusercontent.com
) 的“范围”参数。
新的 Sign-In API ID 令牌流程具有以下优势:
- 精简的一键登录体验
- 您的服务器无需额外调用网络即可获取用户个人资料信息
如需迁移到 ID 令牌流程,请进行以下更改:
Android 客户端
- 如果您请求
GET_ACCOUNTS
(通讯录)权限,请将其移除 - 通过
GoogleSignInOptions.Builder.requestIdToken(...)
配置,将使用GoogleAuthUtil
、Plus.API
、AccountPicker.newChooseAccountIntent()
或AccountManager.newChooseAccountIntent()
的任何代码切换为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.com
和accounts.google.com
从 GoogleAuthUtil 服务器授权代码流程迁移
如果您使用 GoogleAuthUtil
获取服务器授权代码,则应迁移到新的 Sign-In API 授权代码流程。
例如,如果您的 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
(通讯录)权限,请将其移除 - 通过
GoogleSignInOptions.Builder.requestServerAuthCode(...)
配置,将使用GoogleAuthUtil
、Plus.API
、AccountPicker.newChooseAccountIntent()
或AccountManager.newChooseAccountIntent()
的任何代码切换为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); ...