如何在Swift中进行经过身份验证的HTTPS发布?

时间:2015-12-31 10:42:45

标签: swift alamofire

在iPhone应用程序中,我想从经过身份验证的HTTPS图像数据中收集JSON输出。也就是说,等同于:

curl -u "username":"password" \
     -X POST \
     -F "file=@image.png" \
     "https://server.com/blah?param=value"

验证此命令可以使用真实的URL,而不是为了提问而给出的虚拟URL。服务器需要基本身份验证。

关注"上传MultipartFormData" Alamofire readmethis stackoverflow example中的示例,我的第一次尝试使用了Alamofire:

// 'username' and 'password' are string literals. 'img' is a valid UIImage.
let url =  NSURL("https://server.com/blah?param=value")
let dat = UIImagePNGRepresentation(img)
let credentialData = "\(username):\(password)".dataUsingEncoding(NSUTF8StringEncoding)!
let base64Credentials = credentialData.base64EncodedStringWithOptions([])
let headers = ["Authorization": "Basic \(base64Credentials)"]
Alamofire.upload(
        Alamofire.Method.POST,
        url!,
        headers: headers,
        multipartFormData: { multipartFormData in
            multipartFormData.appendBodyPart(data:dat!, name:"file")
        },
        encodingCompletion: { encodingResult in
            switch encodingResult {

            case .Success(let upload, _, _):
                upload.responseString { response in
                    //JSON = response.result.value! as String
                    debugPrint(response)
                }
            case .Failure(let encodingError):
                print(encodingError)
            }
        })

同样,此代码段使用虚拟URL,但我使用真实URL运行代码。这会导致SSL错误:

2015-12-31 05:28:34.733 AutoAlbum[13518:249313] _BSMachError: (os/kern) invalid capability (20)
2015-12-31 05:28:34.733 AutoAlbum[13518:249682] _BSMachError: (os/kern) invalid name (15)
2015-12-31 05:28:35.413 AutoAlbum[13518:249708] CFNetwork SSLHandshake failed (-9824)
2015-12-31 05:28:35.415 AutoAlbum[13518:249708] NSURLSession/NSURLConnection  HTTP load failed (kCFStreamErrorDomainSSL, -9824)
[Request]: <NSMutableURLRequest: 0x7fdeda835040> { URL: https://server.com/blah?param=value }
[Response]: nil
[Data]: 0 bytes
[Result]: FAILURE: Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." UserInfo={_kCFStreamErrorCodeKey=-9824, NSLocalizedRecoverySuggestion=Would you like to connect to the server anyway?, NSUnderlyingError=0x7fdeda84bd90 {Error Domain=kCFErrorDomainCFNetwork Code=-1200 "(null)" UserInfo={_kCFStreamPropertySSLClientCertificateState=0, _kCFNetworkCFStreamSSLErrorOriginalValue=-9824, _kCFStreamErrorDomainKey=3, _kCFStreamErrorCodeKey=-9824}}, NSLocalizedDescription=An SSL error has occurred and a secure connection to the server cannot be made., NSErrorFailingURLKey=https://server.com/blah?param=value, NSErrorFailingURLStringKey=https://server.com/blah?param=value, _kCFStreamErrorDomainKey=3}

当有网络连接时,xcode的iPhone 5s模拟器会发生此错误。

我的第二种方法是:

let PasswordString = "username:password"
let PasswordData = PasswordString.dataUsingEncoding(NSUTF8StringEncoding)
let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
let urlPath: String = "https://server.com/blah?param=value"
let url: NSURL = NSURL(string: urlPath)!
var request: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
request.HTTPMethod = "POST"
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let authString = "Basic \(base64EncodedCredential)"
config.HTTPAdditionalHeaders = ["Authorization" : authString]
let session = NSURLSession(configuration: config)
let img:UIImage = getAsset(asset, size: PHImageManagerMaximumSize)
let dat = String(UIImagePNGRepresentation(img))
let qstr = "file=\(dat)"
request.HTTPBody = qstr.dataUsingEncoding(NSUTF8StringEncoding)
var dataString = ""
session.dataTaskWithRequest(request) {
    (let data, let response, let error) in
    if let httpResponse = response as? NSHTTPURLResponse {
        dataString = String(data: data!, encoding: NSUTF8StringEncoding)!
        print(dataString)
    }
    else {
        print(error)
    }
}.resume()

这导致了同样的ssl错误:

AutoAlbum[15614:316266] CFNetwork SSLHandshake failed (-9824)
2015-12-31 15:47:51.142 AutoAlbum[15614:316266] NSURLSession/NSURLConnection HTTP load failed (kCFStreamErrorDomainSSL, -9824)
Optional(Error Domain=NSURLErrorDomain Code=-1200 "An SSL error has occurred and a secure connection to the server cannot be made." 

关注this example,我尝试将最小tls版本设置为1.0,如下所示: enter image description here

但遇到了同样的错误。

我的代码中是否有人发现问题,或者是否有人建议如何使用iOS技术来执行curl命令的操作?

2 个答案:

答案 0 :(得分:2)

这不是关于身份验证,iOS无法建立与服务器的https连接由于某些原因(Code -1200 means“当尝试建立安全连接因为无法更具体地表达的原因而失败时返回”)。

Curl可以执行此请求,因为它不像ATS那样执行严格的检查,因此您应该正确配置它,并且您尝试执行此操作。 但是你在ATS配置中有一些错误,这就是请求仍然失败的原因。

  1. NSAllowsArbitraryLoads应该有布尔类型,而不是字符串

  2. NSExceptionMinimumTLSVersion应该嵌入到具有域名的字典中(仔细查看您的示例,当您将yourserver.com替换为实际域名时,您会错过部分)。 This is a link官方文档如何正确配置ATS的例外情况,它提供了有关其工作原理的更多详细信息。

  3. 此外,为特定域指定NSAllowsArbitraryLoadsNSExceptionMinimumTLSVersion是多余的,因为NSAllowsArbitraryLoads将覆盖此设置。

答案 1 :(得分:1)

我唯一能看错的是“允许任意加载”键应为布尔类型。

你引用的SO线程建议在“App Transport Security Settings”中添加值为“NO”的“NSTemporaryExceptionRequiresForwardSecrecy”,你试过吗?

您是否可以使用更简单的Web请求测试SSL连接问题,例如GET请求?