如何使用 GIDSignIn 或 GIDAuthentication 刷新 authentication.idToken?

Posted

技术标签:

【中文标题】如何使用 GIDSignIn 或 GIDAuthentication 刷新 authentication.idToken?【英文标题】:How to refresh authentication.idToken with GIDSignIn or GIDAuthentication? 【发布时间】:2016-01-21 15:23:01 【问题描述】:

2015 年 10 月 28 日更新 - Release 2.4.0 of Google Sign-In for ios 似乎已经解决了这个问题,新的 GIDAuthentication 方法 getTokensWithHandler:refreshTokensWithHandler: 根据需要刷新了 idToken 和 accessToken。 GIDSignIn 方法 SignInSilently 也刷新两个令牌。


我正在使用适用于 iOS 的 AWS 移动开发工具包,并且我使用 AWS Cognito Sync sample code 作为基础实现了 Google 登录作为 Cognito 凭证提供程序。登录(以及随后的静默登录)流程正常运行,登录用户可以按预期访问 DynamoDB 等 AWS 资源。

我的问题是user.authentication.idToken 在一小时后过期,此时对 AWS 服务的调用失败并出现身份验证错误。我可以使用

刷新user.authentication.accessToken
[self.googleUser.authentication refreshAccessTokenWithHandler:^(NSString *accessToken, NSError *error) ...

但这不会更新idToken。我也试过打电话

[[GoogleSignIn sharedInstance] signInSilently];

它在会话中第一次被调用时给了我一个有效的 idToken,但是虽然它成功完成它不会在同一会话中的后续调用中刷新 idToken。

我一直在使用

检查/转储令牌内容
https://www.googleapis.com/oauth2/v1/tokeninfo?id_token=<idToken>

https://www.googleapis.com/oauth2/v1/tokeninfo?access_token=<accessToken>

我不确定问题是 GIDSignIn 没有更新 idToken,还是 AWS 应该以某种方式使用 refreshToken 在后端自动刷新用户。无论哪种方式,我都没有想法。

下面的代码 sn-ps。我使用 GoogleSignIn 2.2.0 和 2.3.2 进行了测试,遇到了同样的问题。

...
@interface MySignInClass <GIDSignInDelegate>
...
-(void) signInWithGoogle

    GIDSignIn *signIn = [GIDSignIn sharedInstance];
    signIn.clientID = MY_GOOGLE_CLIENT_ID;
    signIn.shouldFetchBasicProfile = YES;
    signIn.scopes = [NSArray arrayWithObjects:@"https://www.googleapis.com/auth/userinfo.profile", @"openid", nil];
    signIn.delegate = self;
    if([signIn hasAuthInKeychain]) 
        [signIn signInSilently];
     else 
        [signIn signIn];
    

...
- (void)signIn:(GIDSignIn *)signIn 
    didSignInForUser:(GIDGoogleUser *)user
           withError:(NSError *)error 

    if (error != nil) 
        [self handleSignInError:error]; // Handle error
    
    else 
        NSString *idToken = user.authentication.idToken;
        NSDictionary* logins = @@"accounts.google.com": idToken;
        self.credentialsProvider = [[AWSCognitoCredentialsProvider alloc] 
           initWithRegionType:MY_COGNITO_REGION_TYPE
                   identityId:nil
               identityPoolId:MY_COGNITO_IDENTITY_POOL
                       logins:logins];
       AWSServiceConfiguration *configuration = [[AWSServiceConfiguration alloc] 
            initWithRegion:MY_COGNITO_REGION                                                              
       credentialsProvider:self.credentialsProvider];
       AWSServiceManager.defaultServiceManager.defaultServiceConfiguration = configuration;
       // AWSTask stuff removed for simplicity
       AWSTask* task = [self.credentialsProvider getIdentityId];
       ...
    

...
- (void)signIn:(GIDSignIn *)signIn
     didDisconnectWithUser:(GIDGoogleUser *)user
                 withError:(NSError *)error 

    [self handleGoogleSignout]; // Do signout stuff

...

【问题讨论】:

链接到the discussion on AWS forums,以防那边有进展。 我刚刚更新到 iOS 2.4.0 的 Google 登录,它似乎已经修复。如果 idToken 和 accessToken 已过期且身份验证仍然有效,则它们现在都会刷新。这是release notes。我会更新主帖。 【参考方案1】:

像这样拨打GIDSignIn's signInSilently method:

[[GIDSignIn sharedInstance] signInSilently];

这最终将再次使用 idToken 调用您的 signIn:didSignInForUser:withError: 委托方法实现。

我已经验证,通过2.4.0 release of Google Sign-In for iOS,上述使用 signInSilently 的方法确实可以为您提供一个未过期的新 idToken。

【讨论】:

我在测试时在回调中收到令牌。我猜你是说当它过期时,它会发送相同的过期令牌。我会看看我今天是否能找到耐心等待它结束并玩它。如果这不起作用,我有另一个想法...... 我说的是 idToken,而不是访问令牌。 signIn 方法将令牌保存在钥匙串中,因此 signInSilently 应该做同样的事情,但调用 [[GIDSignIn sharedInstance] signInSilently].currentUser.authentication.idToken 返回相同的值。 是的,我明白了,在我的快速测试中,IDToken 被返回给了委托人,但是等了一个小时后,我确实看到它继续返回旧的、现在过期的令牌.我认为实现这一点的唯一方法是再次点击谷歌的令牌端点,但目前尚不清楚如何在使用 GIDSignIn 时做到这一点,因为 GIDSignIn 似乎没有公开原始身份验证代码。【参考方案2】:

我也有这个问题。尽了一切可能,G+ iOS SDK 根本没有更新该令牌。

我们这边的解决方案是将 refresh_token 发送到我们的服务器,他们能够通过访问一个 Google API 来正确更新他们这边的令牌,然后将新令牌发送回我的应用程序。不幸的是,我现在无法访问那里,只能在明天告诉您确切的 API。

【讨论】:

谢谢贝尼。不幸的是,就我而言,后端是 Amazon Cognito,所以我也无法控制它。 我真的希望您能找到正确的解决方案。如果您成功了,请告诉我们。【参考方案3】:

如何在 30 分钟时使用计时器,然后静默调用 signInIn?

【讨论】:

这是一个已修复的错误。 我刚刚发现自己。感谢您的回复,并对过时的帖子表示抱歉。

以上是关于如何使用 GIDSignIn 或 GIDAuthentication 刷新 authentication.idToken?的主要内容,如果未能解决你的问题,请参考以下文章

您必须指定 |clientID|对于 |GIDSignIn|尝试使用 Google 登录时出错

使用 GIDSignIn.sharedInstance.clientID 时的错误代码 =

“GIDSignIn”类型的值没有成员“presentingViewController”

使用 GIDSignIn 登录时出现“没有 URL 方案 com-google-gidconsent 的注册处理程序”错误

如何从ios中的谷歌帐户注销?

如何在 iOS 上使用 Sign In with Google 修复“用户取消了登录流程。”?