You need to enable JavaScript to run this app.
优惠活动
大模型
产品
解决方案
定价
更多

如何在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监听请求响应,再将令牌传递给原生代码:

  1. 配置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")!))
}
  1. 实现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

相关产品推荐
方舟 Agent Plan

超全模态模型 × Harness 升级,最新支持 Deepseek-V4.1-Flash、GLM-5.3 系列、Doubao-Seedream-5.0-pro、Kimi-K3 (部分), 限时 9.9 元起

最近更新时间:2026.07.13 23:55:05