如何通过ASWebAuthenticationSession获取认证请求的Cookies?
问题描述
我正在使用ASWebAuthenticationSession对接私有身份提供商完成认证,流程如下:
- 启动ASWebAuthenticationSession认证流程
- 自定义Scheme的回调被触发
- 需要该请求的所有Cookies用于WKWebView内的用户认证,但回调仅返回自定义Scheme的URL,未返回请求对象。
遇到的核心问题:
- URL存在长度限制,没法通过自定义Scheme的URL传递Cookies
- ASWebAuthenticationSession认证过程中,不会把Cookies存储到HTTPCookieStorage里
相关代码:
session = ASWebAuthenticationSession(url: urlToCall, callbackURLScheme: scheme) { callbackURL, error in let cookie = callbackURL?.absoluteString.split(separator: "=")[1] print("Session is \(cookie)") //How to get Cookies here? }
可行解决方案
1. 借助WKWebView共享存储池获取Cookies
ASWebAuthenticationSession和同域名的WKWebView共享Cookie存储池,只是默认不会直接暴露。可以在回调触发后,用身份提供商的域名加载一个空白页面,再从WKWebView的Cookie存储中读取:
// 记得先设置presentationContextProvider session.presentationContextProvider = self session.start() // 回调处理逻辑 session = ASWebAuthenticationSession(url: urlToCall, callbackURLScheme: scheme) { callbackURL, error in guard callbackURL != nil else { return } // 替换成你的身份提供商域名 let authDomain = "auth.example.com" let config = WKWebViewConfiguration() let webView = WKWebView(frame: .zero, configuration: config) // 加载目标域名的空白页面,触发Cookie同步 webView.load(URLRequest(url: URL(string: "https://\(authDomain)/blank")!)) // 用WKNavigationDelegate替代延迟执行会更可靠 webView.navigationDelegate = self } // 实现WKNavigationDelegate的didFinish方法 extension YourViewController: WKNavigationDelegate { func webView(_ webView: WKWebView, didFinish navigation: WKNavigation!) { let authDomain = "auth.example.com" webView.configuration.websiteDataStore.httpCookieStore.getAllCookies { cookies in // 筛选出目标域名的Cookies let targetCookies = cookies.filter { $0.domain.contains(authDomain) } // 这里拿到的Cookies可以直接用于WKWebView的认证 print(targetCookies) } } }
2. 用回调令牌换取Cookies(推荐)
如果能和私有身份提供商协商,让他们在回调URL里返回一个短期授权令牌,而不是直接传Cookies。之后你可以用这个令牌调用身份提供商的接口,获取所需的Cookies或者认证凭证,再注入到WKWebView中:
session = ASWebAuthenticationSession(url: urlToCall, callbackURLScheme: scheme) { callbackURL, error in guard let callbackURL = callbackURL, let components = URLComponents(url: callbackURL, resolvingAgainstBaseURL: false), let token = components.queryItems?.first(where: { $0.name == "auth_token" })?.value else { return } // 调用令牌兑换接口 let exchangeURL = URL(string: "https://auth.example.com/exchange-token")! var request = URLRequest(url: exchangeURL) request.httpMethod = "POST" request.httpBody = "token=\(token)".data(using: .utf8) URLSession.shared.dataTask(with: request) { data, response, error in guard let httpResponse = response as? HTTPURLResponse, let cookies = HTTPCookie.cookies(withResponseHeaderFields: httpResponse.allHeaderFields as! [String: String], for: exchangeURL) else { return } // 将Cookies注入到目标WKWebView的存储中 let webViewConfig = WKWebViewConfiguration() let targetWebView = WKWebView(frame: .zero, configuration: webViewConfig) cookies.forEach { cookie in targetWebView.configuration.websiteDataStore.httpCookieStore.setCookie(cookie) { // Cookie注入完成,后续可以用这个webView加载需要认证的页面 } } }.resume() }
3. 关闭临时会话模式(备选)
iOS 13及以上可以设置prefersEphemeralWebBrowserSession为false,让ASWebAuthenticationSession共享系统Cookie存储,之后尝试从HTTPCookieStorage中读取。但这个方法兼容性差,系统可能会限制跨域名Cookie的访问:
session = ASWebAuthenticationSession(url: urlToCall, callbackURLScheme: scheme) { callbackURL, error in guard let authURL = URL(string: "https://auth.example.com") else { return } // 尝试从系统Cookie存储中获取 let cookies = HTTPCookieStorage.shared.cookies(for: authURL) print(cookies ?? []) } session.prefersEphemeralWebBrowserSession = false session.presentationContextProvider = self session.start()
内容的提问来源于stack exchange,提问作者user14590906
相关产品推荐
相关产品推荐

