zzh*_*eng 2 google-authentication jwt google-signin google-auth-library
我正在维护一个网站及其移动应用程序(iOS 和 Android)。对于移动应用程序中的 Google 登录,我在服务器端使用google-auth Python 包。
从大约一个月前开始,我开始从服务器端收到与Google登录相关的错误报告。错误消息如下所示:
未找到密钥 ID 728f4016652079b9ed99861bb09bafc5a45baa86 的证书。
服务器端 Google Sign-In 身份验证后端遵循此文档:
from google.oauth2 import id_token
from google.auth.transport import requests
# ...
try:
# The following line may raise ValueError with message:
# Certificate for key id xxxx not found.
id_info = id_token.verify_oauth2_token(google_id_token, requests.Request())
if id_info['aud'] not in VALID_CLIENT_IDS:
logger.error('Invalid aud from Google ID token: %s', id_info['aud'])
raise ValueError('Unverified audience.')
# ...
except ValueError as exc:
logger.error('Fail to verify Google ID token: %s', exc, extra={'request': request})
Run Code Online (Sandbox Code Playgroud)
该错误来自google.auth.jwt 模块当根据 Google 公共证书列表验证 Google 颁发的 JWT 时,
深入研究 google-auth 代码,我可以看到该verify_oauth2_token()函数正在从 URL https://www.googleapis.com/oauth2/v1/certs获取 Google 公共证书。有时,对于从某些 Android 手机发送的某些 Google ID 令牌,似乎无法在该 URL 中找到密钥 ID。
以下是一些可能有用的其他详细信息:
USER_AGENT标题中,我可以看到该错误仅发生在 Android 应用程序 ( USER_AGENT=okhttp/3.11.0) 中。而且这种情况仅发生在部分 Android 设备上,并非全部。aa436c3f63b281ce0d976da0b51a34860ff960eb从 11 月初到现在(12 月底),密钥 id 出现了数十次。我的网站运行在以下环境:
由于我无法用我的 iPhone 或 Android 手机(华为 P20,在法国购买)重现此问题,所以我完全陷入困境。
但是,我的一个朋友现在遇到了这个问题,他从香港购买了 Android 手机。这让我想到,对于某些国家/地区,Google 登录是否可能使用除https://www.googleapis.com/oauth2/v1/certs上的公共证书之外的其他证书?
我不认为这是 google-auth 包中的错误。我想知道你们中是否有人听说过这个错误,并且可以给我一些关于其可能原因的提示?
提前致谢!
好吧,我终于想通了。我在这里发布我的发现,希望对其他人有帮助。
服务器端Python代码没有任何问题。失败的原因是客户端应用程序提交了过期的 Google ID 令牌。
这是我的 LoginActivity 的固定版本:
...
@OnClick(R.id.google_sign_in_button)
void loginWithGoogle() {
//
// If user has already signed in to our app with Google, sign him out first.
//
// NOTE: This step is required, or the ID token might not pass the server-side validation!
//
// After sign-in, we need to get the user's ID token issued and signed by Google, and send
// it back to our server for validation.
//
// Google is rotating its OAuth2 certificate regularly, so an old ID token issued long time
// ago by Google might not pass the server-side validation -- if the certificate used to
// sign the ID token has expired.
//
// This may happen when user has already signed in to our app with Google. In such case,
// the ID token we get from the user's Google account is obsolete. Our server will fail to
// validate it, with the error message:
//
// Fail to verify Google ID token: Certificate for key id xxx not found.
//
// Google recommends using the `silentSignIn` method for the already-signed-in user
// (see step 2 of: https://developers.google.com/identity/sign-in/android/backend-auth).
// For the sake of simplicity, we don't do that. Instead, we go directly to step 3
// by signing user out, giving him the option to sign-in again.
//
final GoogleSignInAccount account = GoogleSignIn.getLastSignedInAccount(this);
if (account != null) {
// User has already signed in: Sign out and sign in again.
// NOTE: THIS IS THE FIX TO MY PROBLEM.
mGoogleSignInClient.signOut().addOnCompleteListener(this, new OnCompleteListener<Void>() {
@Override
public void onComplete(@NonNull Task<Void> task) {
startGoogleSignInActivity();
}
});
} else {
// User is not yet signed in: Start the Google sign-in flow.
startGoogleSignInActivity();
}
}
private void startGoogleSignInActivity() {
final Intent intent = mGoogleSignInClient.getSignInIntent();
startActivityForResult(intent, REQUEST_LOGIN_WITH_GOOGLE);
}
Run Code Online (Sandbox Code Playgroud)
关键点是:我需要检查用户是否已经使用 Google 登录。如果是,我需要注销用户并重新启动“使用 Google 登录”活动。
由于 Android 对 Google 帐户有本机支持,我想如果用户已经通过身份验证(在某些其他应用程序或系统范围内),操作系统可能会缓存用户的 Google 帐户。但该缓存帐户可能包含过期的 ID 令牌。强制用户注销并重新登录将为我提供一个全新的 ID 令牌。
这也解释了为什么我的iOS应用程序没有这个问题。因为iOS从不缓存用户的Google帐户。
| 归档时间: |
|
| 查看次数: |
2912 次 |
| 最近记录: |