如何在Swift WebView中获取请求URL并拦截登录令牌?
Swift WebView登录令牌拦截解决方案
方法1:通过WKNavigationDelegate拦截请求URL
使用WKNavigationDelegate的webView(_:decidePolicyFor:decisionHandler:)方法,该方法能直接获取请求的原始URL(而非当前页面URL),适合拦截登录成功后的重定向请求或带令牌的回调URL。
示例代码:
class WebViewController: UIViewController, WKNavigationDelegate { var webView: WKWebView! override func viewDidLoad() { super.viewDidLoad() let config = WKWebViewConfiguration() webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self view.addSubview(webView) // 加载第三方登录页面 let loginUrl = URL(string: "https://your-third-party-login-url.com")! webView.load(URLRequest(url: loginUrl)) } func webView(_ webView: WKWebView, decidePolicyFor navigationAction: WKNavigationAction, decisionHandler: @escaping (WKNavigationActionPolicy) -> Void) { // 检查请求URL是否包含令牌参数(根据第三方服务回调格式调整参数名,如access_token、token) guard let requestUrl = navigationAction.request.url, let components = URLComponents(url: requestUrl, resolvingAgainstBaseURL: false), let tokenItem = components.queryItems?.first(where: { $0.name == "access_token" }), let token = tokenItem.value else { decisionHandler(.allow) return } // 成功获取令牌,执行存储、跳转主页等逻辑 print("获取到令牌:\(token)") // 阻止WebView继续导航到主页 decisionHandler(.cancel) // 此处可跳转至App主页 // self.navigationController?.pushViewController(MainViewController(), animated: true) } }
方法2:处理服务器重定向场景
若第三方登录成功后通过服务器重定向返回令牌,可在webView(_:didReceiveServerRedirectForProvisionalNavigation:)中监听重定向请求,结合上述decidePolicy方法做双重校验:
func webView(_ webView: WKWebView, didReceiveServerRedirectForProvisionalNavigation navigation: WKNavigation!) { if let redirectUrl = webView.url { // 检查重定向URL中的令牌参数 if let components = URLComponents(url: redirectUrl, resolvingAgainstBaseURL: false), let token = components.queryItems?.first(where: { $0.name == "access_token" })?.value { print("重定向中获取令牌:\(token)") // 停止WebView加载 webView.stopLoading() // 执行令牌处理与页面跳转逻辑 } } }
方法3:注入JavaScript拦截AJAX请求返回的令牌
如果令牌通过AJAX请求(而非URL参数)返回,可注入JavaScript监听请求响应,再将令牌传递给原生代码:
- 配置WKWebView的消息处理器与注入脚本:
override func viewDidLoad() { super.viewDidLoad() let config = WKWebViewConfiguration() // 添加消息处理器,接收JS传递的令牌 config.userContentController.add(self, name: "tokenHandler") // 注入拦截AJAX和fetch请求的脚本 let scriptSource = """ // 拦截XMLHttpRequest const originalOpen = XMLHttpRequest.prototype.open; XMLHttpRequest.prototype.open = function(method, url) { this.addEventListener('load', function() { if (url.includes('login/callback')) { // 根据第三方登录回调接口调整 const response = JSON.parse(this.responseText); if (response.access_token) { window.webkit.messageHandlers.tokenHandler.postMessage(response.access_token); } } }); originalOpen.apply(this, arguments); }; // 拦截fetch请求 const originalFetch = fetch; window.fetch = async function(url, options) { const response = await originalFetch(url, options); if (url.includes('login/callback')) { const data = await response.json(); if (data.access_token) { window.webkit.messageHandlers.tokenHandler.postMessage(data.access_token); } } return response; }; """ let userScript = WKUserScript(source: scriptSource, injectionTime: .atDocumentStart, forMainFrameOnly: true) config.userContentController.addUserScript(userScript) webView = WKWebView(frame: view.bounds, configuration: config) webView.navigationDelegate = self view.addSubview(webView) // 加载登录页 webView.load(URLRequest(url: URL(string: "https://your-third-party-login-url.com")!)) }
- 实现
WKScriptMessageHandler接收令牌:
extension WebViewController: WKScriptMessageHandler { func userContentController(_ userContentController: WKUserContentController, didReceive message: WKScriptMessage) { if message.name == "tokenHandler", let token = message.body as? String { print("JS传递的令牌:\(token)") // 执行令牌处理逻辑 webView.stopLoading() // 跳转至App主页 } } }
注意事项
- 先确认第三方服务的回调格式:是URL参数携带令牌,还是AJAX响应返回,再针对性选择方法。
- 拦截令牌后,调用
decisionHandler(.cancel)或webView.stopLoading()阻止WebView继续加载主页。 - 令牌需用
Keychain Services做安全存储,避免使用UserDefaults。
内容的提问来源于stack exchange,提问作者Miiko
相关产品推荐
相关产品推荐

