如何在经过身份验证后退出Google

时间:2016-06-21 05:55:40

标签: ios swift authentication firebase viewcontroller

因此,我的应用可以选择使用Google登录。单击Google提供的按钮后,将打开Web视图并让用户输入其凭据。在允许应用访问他们的信息后,应用程序然后签署用户并将SignInViewController更改为TabBarController(他们现在可以相应地进行交互)。

当用户按下“注销”按钮时,会按照预期将其定向到登录屏幕。但奇怪的是,如果用户再次按下谷歌按钮,他们会自动登录,根本没有进一步的身份验证,也没有删除帐户的选项。他们是否有办法清除谷歌帐户凭据以保护用户免遭意外盗窃?

登录功能:

func signIn(signIn: GIDSignIn!, didSignInForUser user: GIDGoogleUser!, withError error: NSError!) {
    if let error = error {
        print(error.localizedDescription)
        return
    }
    let authentication = user.authentication
    let credential = FIRGoogleAuthProvider.credentialWithIDToken(authentication.idToken, accessToken: authentication.accessToken)
    FIRAuth.auth()?.signInWithCredential(credential) { (user, error) in
        // ...
        SignInViewController().signedIn(user)
    }
    // ...
}

退出功能

func signOutOverride() {
    do {
        try! FIRAuth.auth()!.signOut()
        CredentialState.sharedInstance.signedIn = false
        // Set the view to the login screen after signing out
        let storyboard = UIStoryboard(name: "SignIn", bundle: nil)
        let loginVC = storyboard.instantiateViewControllerWithIdentifier("SignInVC") as! SignInViewController
        let appDelegate = UIApplication.sharedApplication().delegate as! AppDelegate
        appDelegate.window?.rootViewController = loginVC
    } catch let signOutError as NSError {
        print ("Error signing out: \(signOutError)")
    }
}

7 个答案:

答案 0 :(得分:44)

<强>夫特

尝试GIDSignIn.sharedInstance().signOut()

目标 - c

[[GIDSignIn sharedInstance] signOut];

答案 1 :(得分:12)

是的,就像@Rahul所说,以下代码是正确的方式。

GIDSignIn.sharedInstance().signOut()

https://developers.google.com/identity/sign-in/ios/sign-in?ver=swift#sign_out_the_user

答案 2 :(得分:3)

为什么用户注销后不需要租用密码?

我想澄清一下为什么用户立即重新登录以及为什么其中一些解决方案在iOS 13上不起作用。

以下内容实际上确实使用户退出了您的应用程序:

GIDSignIn.sharedInstance().signOut()

但是它不会在Safari本身中从Google注销用户!自己尝试一下,在您的应用中登录一个Google帐户。从该应用程序注销,然后在Safari浏览器中转到account.google.com,该帐户仍将登录!因此,这些Cookie正在与默认的Safari浏览器共享,为什么?

经过一番调查后,我在处理实际交互式身份验证流的OIDExternalUserAgentiOS类中发现了这一点。

  // iOS 12 and later, use ASWebAuthenticationSession
  if (@available(iOS 12.0, *)) {
    // ASWebAuthenticationSession doesn't work with guided access (rdar://40809553)
    if (!UIAccessibilityIsGuidedAccessEnabled()) {
      __weak OIDExternalUserAgentIOS *weakSelf = self;
      NSString *redirectScheme = request.redirectScheme;
      ASWebAuthenticationSession *authenticationVC =
          [[ASWebAuthenticationSession alloc] initWithURL:requestURL
                                        callbackURLScheme:redirectScheme
                                        completionHandler:^(NSURL * _Nullable callbackURL,
                                                            NSError * _Nullable error) {
        __strong OIDExternalUserAgentIOS *strongSelf = weakSelf;
        if (!strongSelf) {
            return;
        }
        strongSelf->_webAuthenticationVC = nil;
        if (callbackURL) {
          [strongSelf->_session resumeExternalUserAgentFlowWithURL:callbackURL];
        } else {
          NSError *safariError =
              [OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
                               underlyingError:error
                                   description:nil];
          [strongSelf->_session failExternalUserAgentFlowWithError:safariError];
        }
      }];
#if __IPHONE_OS_VERSION_MAX_ALLOWED >= 130000
      if (@available(iOS 13.0, *)) {
          authenticationVC.presentationContextProvider = self;
      }
#endif
      _webAuthenticationVC = authenticationVC;
      openedUserAgent = [authenticationVC start];
    }
  }
  // iOS 11, use SFAuthenticationSession
  if (@available(iOS 11.0, *)) {
    // SFAuthenticationSession doesn't work with guided access (rdar://40809553)
    if (!openedUserAgent && !UIAccessibilityIsGuidedAccessEnabled()) {
      __weak OIDExternalUserAgentIOS *weakSelf = self;
      NSString *redirectScheme = request.redirectScheme;
      SFAuthenticationSession *authenticationVC =
          [[SFAuthenticationSession alloc] initWithURL:requestURL
                                     callbackURLScheme:redirectScheme
                                     completionHandler:^(NSURL * _Nullable callbackURL,
                                                         NSError * _Nullable error) {
        __strong OIDExternalUserAgentIOS *strongSelf = weakSelf;
        if (!strongSelf) {
            return;
        }
        strongSelf->_authenticationVC = nil;
        if (callbackURL) {
          [strongSelf->_session resumeExternalUserAgentFlowWithURL:callbackURL];
        } else {
          NSError *safariError =
              [OIDErrorUtilities errorWithCode:OIDErrorCodeUserCanceledAuthorizationFlow
                               underlyingError:error
                                   description:@"User cancelled."];
          [strongSelf->_session failExternalUserAgentFlowWithError:safariError];
        }
      }];
      _authenticationVC = authenticationVC;
      openedUserAgent = [authenticationVC start];
    }
  }
  // iOS 9 and 10, use SFSafariViewController
  if (@available(iOS 9.0, *)) {
    if (!openedUserAgent && _presentingViewController) {
      SFSafariViewController *safariVC =
          [[SFSafariViewController alloc] initWithURL:requestURL];
      safariVC.delegate = self;
      _safariVC = safariVC;
      [_presentingViewController presentViewController:safariVC animated:YES completion:nil];
      openedUserAgent = YES;
    }
  }
  // iOS 8 and earlier, use mobile Safari
  if (!openedUserAgent){
    openedUserAgent = [[UIApplication sharedApplication] openURL:requestURL];
  }

如果您使用的是iOS 12或更高版本,它将使用ASWebAuthenticationService,默认情况下它会与Safari共享Cookie!对于iOS 11、10、9、8,情况类似,执行方法不同。在Apple文档here中,有关SFSafariViewController的事情也很有趣:

在iOS 9和10中,它[SFSafariViewController]与Safari共享Cookie和其他网站数据。

出现google登录页面时,它会与Safari共享Cookie。这就是为什么我们没有完全退出Google的原因。实际上,这似乎完全是故意的。

我们如何注销用户?

这适用于GIDSignIn支持的所有iOS版本:

let url = URL(string: "https://accounts.google.com/Logout")!
UIApplication.shared.open(url, options: [:], completion: nil)

不幸的是,这会将用户重定向到应用程序外部。但是您可以在调用open之前在UIAlertController中解释其必要性。

答案 3 :(得分:1)

在使用GoogleSignIn SDK之后,想详细说明先前的答案。

我看到了signOut()disconnect()方法,并且想知道它们之间有什么区别。

signOut()是一个同步呼叫:

// Immediately sets GIDSignIn.sharedInstance()?.currentUser to nil. 
// For example, if the user is already signed in:

print(GIDSignIn.sharedInstance()?.currentUser != nil) // true - signed in
GIDSignIn.sharedInstance()?.signOut()
print(GIDSignIn.sharedInstance()?.currentUser != nil) // false - signed out

disconnect()允许用户注销应用程序的访问权限。我认为这意味着如果他们选择再次登录,他们将需要重新授予对您的应用程序的任何权限。

根据Google's Developer Docs,如果用户选择断开连接,那么您将需要删除存储在应用程序中的任何用户Google数据。

此外,disconnect()是异步的。断开连接的结果将返回到GIDSignInDelegate.sign(_:didDisconnectWith:withError:)方法。

// Also sets GIDSignIn.sharedInstance()?.currentUser to nil. 
// Asynchronous call. If for example the user was already signed in:

print(GIDSignIn.sharedInstance()?.currentUser != nil) // true - signed in
GIDSignIn.sharedInstance()?.disconnect()
print(GIDSignIn.sharedInstance()?.currentUser != nil) // true - still signed in

// MARK: - GIDSignInDelegate
func sign(_ signIn: GIDSignIn!, didDisconnectWith user: GIDGoogleUser!, withError error: Error!) {
    print(GIDSignIn.sharedInstance()?.currentUser != nil) // false - signed out

    // Remove any data saved to your app obtained from Google's APIs for this user.
}

答案 4 :(得分:0)

  public func logOut(on:UIViewController){

    let firebaseAuth = Auth.auth()
    do {
        try  firebaseAuth.signOut()
            GIDSignIn.sharedInstance().signOut()
            GIDSignIn.sharedInstance().disconnect()

        if let url = NSURL(string:  "https://www.google.com/accounts/Logout?continue=https://appengine.google.com/_ah/logout?continue=https://google.com"){
            UIApplication.shared.open(url as URL, options: [:]) { (true) in
                let appDel:AppDelegate = UIApplication.shared.delegate as! AppDelegate
                appDel.window?.rootViewController = LoginViewController()
            }
        }
    } catch let signOutError as NSError {
        Help.shared.Snack(messageString: "Error signing out: \(signOutError)" 
)
        print ("Error signing out: %@", signOutError)
    }
}

答案 5 :(得分:0)

如果有人还在看这个,我想我已经开始要求OP了。

所以我的情况是这样的:

GIDSignIn *gidObject = [GIDSignIn sharedInstance];
[gidObject signOut];
[gidObject disconnect];


NSString *logOutUrl = @"https://www.google.com/accounts/Logout";
[[UIApplication sharedApplication] openURL:[NSURL URLWithString: logOutUrl] options:@{} completionHandler:nil];

如上所述,我已将应用程序转到google注销网址。对于我们的工作流程,我希望用户积极地知道他们正在注销。有点像用户的支票。 我错了是GIDSignIn的签出和断开连接。在我退出之前,请先断开连接。当我拥有这种方式时,无论用户是什么用户,他们都永远不会“退出”谷歌。当我撤消断开连接并注销后,它会将用户从他们的Google帐户中注销,这就是我们想要的。

从逻辑上讲,我认为在与应用断开连接之前,先退出是可以的。

答案 6 :(得分:-1)

尝试我的代码。

@IBAction func onClickSignOut(_ sender: UIButton) {

    GIDSignIn.sharedInstance()?.signOut()

    //        if GIDSignIn.sharedInstance()?.currentUser == nil {//Logged out
    //            self.navigationController?.popToRootViewController(animated: true)
    //        } else {//Not logged out
    //            //Your code here
    //        }

    /* check for user's token */
    if GIDSignIn.sharedInstance().hasAuthInKeychain() {
        //hasAuthInKeychain() : Checks whether the user has either currently signed in or has previous authentication saved in keychain.
        //Not logged out
        //Write your code here
        //......
    } else {
        //Logged out
        //Write logged out code here
        //EX:
        self.navigationController?.popToRootViewController(animated: true)
    }

}