因此,我的应用可以选择使用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)")
}
}
答案 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)
}
}