【问题标题】:401 challenges with URLSession for NTLMNTLM 的 URLSession 的 401 挑战
【发布时间】:2019-09-13 21:52:08
【问题描述】:

我正在使用带有委托的自定义 URLSession 来处理从我们的 NTLM 身份验证 Web api 收到的 401 挑战。我希望只收到第一个 api 调用的挑战,但是我调用的每个唯一端点都会收到一个挑战。有没有办法在每次调用时提供存储的凭据以避免每次都出现 401?我的基本会话设置如下。

let config = URLSessionConfiguration.default

let delegate = MySessionDelegate()
let session = URLSession(configuration: config, delegate: delegate, delegateQueue: nil)

【问题讨论】:

    标签: swift


    【解决方案1】:

    这是我在使用 NTLM 身份验证处理 API 时发现的解决方案。本质上,您需要将 URLSessionConfiguration 实例的委托设置为 ViewController 的类(或任何 NSObject 的子类)并实现 URLSessionDelegate 协议的 func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) 函数。

    身份验证的处理方式是,当URLSession 发出请求时,它首先协商身份验证方法(参见NSURLProtectionSpace Authentication Method Constants),然后根据您选择的身份验证方法(在这种情况下,我们拒绝所有不是@987654327 @),我们通过服务器进行身份验证。

    以下代码已使用 Swift 5.1 和 Xcode 11 进行了测试:

    import Cocoa
    import PlaygroundSupport
    
    PlaygroundPage.current.needsIndefiniteExecution = true
    
    class NTLMAuthentication: NSObject {
    
        private let baseURL = "<insert base URL here>"
    
        private let username: String
        private let password: String
    
        lazy private var session: URLSession = {
            let config = URLSessionConfiguration.default
            return URLSession(configuration: config, delegate: self, delegateQueue: nil)
        }()
    
        init(username: String, password: String) {
            self.username = username
            self.password = password
        }
    
        func authenticate() {
            let url = URL(string: baseURL)
            let request = URLRequest(url: url!)
    
            let task = session.dataTask(with: request) { data, response, error in
                guard error == nil else {
                    print("An error occurred")
                    return
                }
    
                let htmlData = String(bytes: data!, encoding: String.Encoding.utf8)
                print(htmlData)
            }
            task.resume()
        }
    }
    
    extension NTLMAuthentication : URLSessionDelegate {
        func urlSession(_ session: URLSession, didReceive challenge: URLAuthenticationChallenge, completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {
    
            print("got challenge")
            print(challenge.protectionSpace.authenticationMethod)
    
            guard challenge.previousFailureCount == 0 else {
                print("too many failures")
                completionHandler(.cancelAuthenticationChallenge, nil)
                return
            }
    
            guard challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM else {
                completionHandler(.rejectProtectionSpace, nil)
                return
            }
    
            let credentials = URLCredential(user: self.username, password: self.password, persistence: .forSession)
            completionHandler(.useCredential, credentials)
        }
    }
    

    请注意,PlaygroundPage.current.needsIndefiniteExecution = true 行是在 Playground 中运行此代码所必需的,否则代码将无法在 Playground 终止之前完成运行。

    【讨论】:

    • 这并没有解决问题。这个解决方案仍然会为每个新网址带来 401 挑战
    猜你喜欢
    • 1970-01-01
    • 1970-01-01
    • 2019-01-28
    • 2019-09-28
    • 1970-01-01
    • 2015-07-07
    • 2015-03-29
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多