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

URLSessionTaskDelegate认证挑战函数未触发,求Digest Auth替代方案

解决URLSession与Shelly设备Digest Authentication兼容问题

一、替代认证方式:预配置凭证到Session配置

不需要等挑战代理触发,直接把用户名密码封装成凭证,提前配置给URLSession:

let username = "你的用户名"
let password = "你的密码"
let credential = URLCredential(user: username, password: password, persistence: .forSession)

let config = URLSessionConfiguration.default
// 指定目标设备的防护空间,匹配Digest认证
config.urlCredentialStorage?.set(credential, for: URLProtectionSpace(
    host: "192.168.1.99",
    port: 80,
    protocol: "http",
    realm: nil,
    authenticationMethod: NSURLAuthenticationMethodHTTPDigest
))

let session = URLSession(configuration: config, delegate: self, delegateQueue: nil)
// 正常发起请求即可

原理是提前告知URLSession对应设备的认证信息,即使设备的Digest响应格式略有偏差,Session也会尝试自动匹配使用该凭证。

二、更低层级设置Authentication头:自定义URLProtocol

如果上面的方法无效,可以通过自定义URLProtocol绕过URLSession对Auth头的限制,完全手动控制请求头:

  1. 实现自定义Protocol子类:
class CustomShellyAuthProtocol: URLProtocol {
    override class func canInit(with request: URLRequest) -> Bool {
        // 只处理Shelly设备的请求
        return request.url?.host == "192.168.1.99"
    }

    override class func canonicalRequest(for request: URLRequest) -> URLRequest {
        return request
    }

    override func startLoading() {
        guard let url = request.url else {
            client?.urlProtocol(self, didFailWithError: NSError(domain: "CustomAuth", code: -1, userInfo: [NSLocalizedDescriptionKey: "无效URL"]))
            return
        }

        var mutableRequest = request
        // 填入你在Playground验证有效的Digest Auth头内容
        let authHeader = "Digest username=\"你的用户名\", realm=\"shelly\", nonce=\"...\", uri=\"/relay/0?turn=on&timer=30\", response=\"...\""
        mutableRequest.setValue(authHeader, forHTTPHeaderField: "Authorization")

        let task = URLSession.shared.dataTask(with: mutableRequest) { [weak self] data, response, error in
            guard let self = self else { return }
            if let error = error {
                self.client?.urlProtocol(self, didFailWithError: error)
                return
            }
            if let response = response {
                self.client?.urlProtocol(self, didReceive: response, cacheStoragePolicy: .notAllowed)
            }
            if let data = data {
                self.client?.urlProtocol(self, didLoad: data)
            }
            self.client?.urlProtocolDidFinishLoading(self)
        }
        task.resume()
    }

    override func stopLoading() {}
}
  1. 在App启动时注册这个Protocol:
// 比如在AppDelegate的didFinishLaunchingWithOptions方法中
URLProtocol.registerClass(CustomShellyAuthProtocol.self)

这样所有指向Shelly设备的请求都会走自定义逻辑,你可以完全控制HTTP头的设置,不受URLSession的限制。

三、手动触发认证流程(针对设备响应不规范的情况)

既然httpbin能正常触发代理,说明Shelly设备的401响应可能不符合标准Digest格式,你可以在请求完成回调里手动检查响应,触发认证:

func urlSession(_ session: URLSession, task: URLSessionTask, didCompleteWithError error: Error?) {
    if let httpResponse = task.response as? HTTPURLResponse, httpResponse.statusCode == 401 {
        if let authHeader = httpResponse.allHeaderFields["WWW-Authenticate"] as? String, authHeader.starts(with: "Digest") {
            // 手动构造凭证并触发认证
            let credential = URLCredential(user: "你的用户名", password: "你的密码", persistence: .forSession)
            task.authenticate(with: credential) { success, error in
                if success {
                    task.resume()
                }
            }
        }
    }
}

内容的提问来源于stack exchange,提问作者MindSpiker

相关产品推荐
方舟 Agent Plan

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

最近更新时间:2026.06.23 00:06:08