如何从 iOS ADAL 身份验证注销?
How to LogOut from iOS ADAL Authentication?
我已将 ADAL 库集成到我的 iOS 应用程序中,并且运行良好。但现在我想从 ADAL 注销。我怎样才能注销?
使用 ADAL 交互流时,有两个地方存储登录状态。第一个是完全由应用程序控制的令牌缓存。调用 [authContext.tokenCacheStore removeAllWithError:&error] 是清除所有缓存令牌并阻止 ADAL 在根本不启动浏览器的情况下登录的好方法。
但是,服务器也会在浏览器 cookie 中跟踪登录状态。服务器将记住用户已登录到服务器,直到 cookie 超时或被删除。当 ADAL 检查缓存但未找到合适的令牌时,它将启动 webView。服务器将找到一个 cookie,然后以静默方式让用户登录。浏览器 cookie 在很大程度上对 ADAL 是隐藏的。 ADAL 库可能会提供清除所有 cookie 的注销功能,但如果应用出于某种原因依赖于其他 cookie,这会产生副作用。
有几种方法可以解决这个问题。如果您只是想注销并且不介意清除所有 webView cookie,那么在清除缓存后,请按照此处所述清除所有浏览器 cookie:
How to delete all cookies of UIWebView?
这是核选项。另一个更微妙的选择是清除缓存,然后在调用带有 ADPromptBehavior 参数的 aquireToken 时使用 AD_PROMPT_ALWAYS 值。当您使用 AD_PROMPT_ALWAYS 时,会向 AAD 发送一个标志,使其忽略 cookie 并向用户显示一个新提示。这会保留 cookie,因此从技术上讲,用户实际上并未退出。对用户来说,他们似乎已注销并且可以稍后再次登录。当他们再次登录时,他们可以根据需要选择不同的用户。
这也是您处理多用户登录的方式。如果您已经有一个用户登录,但想添加另一个用户,请不要清除缓存并在下次调用 acquireToken 时传递 AD_PROMPT_ALWAYS。服务器将显示一个新的登录提示和 return 一个新令牌。该令牌将存储在该 ADAL 缓存中。您可以通过调用 acquireToken 并传递 userId 来获取特定用户的令牌。
更新 Rich 的出色回答。首先,接口随着最新的 ADAL 版本发生了变化,您需要通过这种方式访问令牌缓存:
#import <ADAL/ADKeychainTokenCache.h>
[...]
[[ADKeychainTokenCache defaultKeychainCache] removeAllForClientId:ADFS_CLIENT_ID error:&error];
要清除 cookie,我建议只删除重要的而不是全部清除:
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [cookieJar cookies]) {
if ([cookie.name isEqualToString:@"MSISAuth"] ||
[cookie.name isEqualToString:@"MSISAuthenticated"] ||
[cookie.name isEqualToString:@"MSISLoopDetectionCookie"]) {
[cookieJar deleteCookie:cookie];
}
}
(我发现 AD_PROMPT_ALWAYS 在较旧的 ADFS 安装上不起作用,被迫删除 cookie。)
这个 swift 3 代码对我有用 (ADAL 2.5.1):
销毁密钥库:
guard let clientId = getAuthConfig().clientId else {
// freak out
print("Auth.logout: I freaked out getting the client ID ")
return
}
ADKeychainTokenCache.defaultKeychain().removeAll(forClientId: clientId, error: nil)
并清除 cookie:
let cookieJar = HTTPCookieStorage.shared
guard let cookies = cookieJar.cookies else { return }
let cookiesArr = Array(cookies)
for cookie: HTTPCookie in cookiesArr {
print(cookie.name)
if (cookie.name == "SignInStateCookie" || cookie.name == "ESTSAUTHPERSISTENT" || cookie.name == "ESTSAUTHLIGHT" || cookie.name == "ESTSAUTH" || cookie.name == "ESTSSC") {
cookieJar.deleteCookie(cookie)
}
}
根据最新版本更新:
没有我们可以控制并允许我们将其全部删除的共享 cookie:
let cookieJar = HTTPCookieStorage.shared
if let cookies = cookieJar.cookies {
let cookiesArray = Array(cookies)
for cookie: HTTPCookie in cookiesArray {
if (cookie.name == "SignInStateCookie" ||
cookie.name == "ESTSAUTHPERSISTENT" ||
cookie.name == "ESTSAUTHLIGHT" ||
cookie.name == "ESTSAUTH" ||
cookie.name == "ESTSSC" ||
cookie.name == "MSISAuth" ||
cookie.name == "MSISAuthenticated" ||
cookie.name == "MSISLoopDetectionCookie" ) {
cookieJar.deleteCookie(cookie)
}
}
}
所以这实际上是行不通的。
我找到的解决方案是在MSALInteractiveTokenParameters
配置中选择提示类型为login
:
let webviewParameters = MSALWebviewParameters.init(authPresentationViewController: VC)
let parameters = MSALInteractiveTokenParameters(
scopes: scopes,
webviewParameters: webviewParameters
)
parameters.promptType = .login
我已将 ADAL 库集成到我的 iOS 应用程序中,并且运行良好。但现在我想从 ADAL 注销。我怎样才能注销?
使用 ADAL 交互流时,有两个地方存储登录状态。第一个是完全由应用程序控制的令牌缓存。调用 [authContext.tokenCacheStore removeAllWithError:&error] 是清除所有缓存令牌并阻止 ADAL 在根本不启动浏览器的情况下登录的好方法。
但是,服务器也会在浏览器 cookie 中跟踪登录状态。服务器将记住用户已登录到服务器,直到 cookie 超时或被删除。当 ADAL 检查缓存但未找到合适的令牌时,它将启动 webView。服务器将找到一个 cookie,然后以静默方式让用户登录。浏览器 cookie 在很大程度上对 ADAL 是隐藏的。 ADAL 库可能会提供清除所有 cookie 的注销功能,但如果应用出于某种原因依赖于其他 cookie,这会产生副作用。
有几种方法可以解决这个问题。如果您只是想注销并且不介意清除所有 webView cookie,那么在清除缓存后,请按照此处所述清除所有浏览器 cookie:
How to delete all cookies of UIWebView?
这是核选项。另一个更微妙的选择是清除缓存,然后在调用带有 ADPromptBehavior 参数的 aquireToken 时使用 AD_PROMPT_ALWAYS 值。当您使用 AD_PROMPT_ALWAYS 时,会向 AAD 发送一个标志,使其忽略 cookie 并向用户显示一个新提示。这会保留 cookie,因此从技术上讲,用户实际上并未退出。对用户来说,他们似乎已注销并且可以稍后再次登录。当他们再次登录时,他们可以根据需要选择不同的用户。
这也是您处理多用户登录的方式。如果您已经有一个用户登录,但想添加另一个用户,请不要清除缓存并在下次调用 acquireToken 时传递 AD_PROMPT_ALWAYS。服务器将显示一个新的登录提示和 return 一个新令牌。该令牌将存储在该 ADAL 缓存中。您可以通过调用 acquireToken 并传递 userId 来获取特定用户的令牌。
更新 Rich 的出色回答。首先,接口随着最新的 ADAL 版本发生了变化,您需要通过这种方式访问令牌缓存:
#import <ADAL/ADKeychainTokenCache.h>
[...]
[[ADKeychainTokenCache defaultKeychainCache] removeAllForClientId:ADFS_CLIENT_ID error:&error];
要清除 cookie,我建议只删除重要的而不是全部清除:
NSHTTPCookieStorage *cookieJar = [NSHTTPCookieStorage sharedHTTPCookieStorage];
for (NSHTTPCookie *cookie in [cookieJar cookies]) {
if ([cookie.name isEqualToString:@"MSISAuth"] ||
[cookie.name isEqualToString:@"MSISAuthenticated"] ||
[cookie.name isEqualToString:@"MSISLoopDetectionCookie"]) {
[cookieJar deleteCookie:cookie];
}
}
(我发现 AD_PROMPT_ALWAYS 在较旧的 ADFS 安装上不起作用,被迫删除 cookie。)
这个 swift 3 代码对我有用 (ADAL 2.5.1):
销毁密钥库:
guard let clientId = getAuthConfig().clientId else {
// freak out
print("Auth.logout: I freaked out getting the client ID ")
return
}
ADKeychainTokenCache.defaultKeychain().removeAll(forClientId: clientId, error: nil)
并清除 cookie:
let cookieJar = HTTPCookieStorage.shared
guard let cookies = cookieJar.cookies else { return }
let cookiesArr = Array(cookies)
for cookie: HTTPCookie in cookiesArr {
print(cookie.name)
if (cookie.name == "SignInStateCookie" || cookie.name == "ESTSAUTHPERSISTENT" || cookie.name == "ESTSAUTHLIGHT" || cookie.name == "ESTSAUTH" || cookie.name == "ESTSSC") {
cookieJar.deleteCookie(cookie)
}
}
根据最新版本更新:
没有我们可以控制并允许我们将其全部删除的共享 cookie:
let cookieJar = HTTPCookieStorage.shared
if let cookies = cookieJar.cookies {
let cookiesArray = Array(cookies)
for cookie: HTTPCookie in cookiesArray {
if (cookie.name == "SignInStateCookie" ||
cookie.name == "ESTSAUTHPERSISTENT" ||
cookie.name == "ESTSAUTHLIGHT" ||
cookie.name == "ESTSAUTH" ||
cookie.name == "ESTSSC" ||
cookie.name == "MSISAuth" ||
cookie.name == "MSISAuthenticated" ||
cookie.name == "MSISLoopDetectionCookie" ) {
cookieJar.deleteCookie(cookie)
}
}
}
我找到的解决方案是在MSALInteractiveTokenParameters
配置中选择提示类型为login
:
let webviewParameters = MSALWebviewParameters.init(authPresentationViewController: VC)
let parameters = MSALInteractiveTokenParameters(
scopes: scopes,
webviewParameters: webviewParameters
)
parameters.promptType = .login