How to make an HTTP request + basic auth in Swift

我有一个带有基本身份验证的 RESTFull 服务,我想从 iOS + swift 调用它。我必须如何以及在哪里为此请求提供凭证?

我的代码(抱歉,我刚开始学习 iOS/obj-c/swift) :

class APIProxy: NSObject {
var data: NSMutableData = NSMutableData()
    

func connectToWebApi() {
var urlPath = "http://xx.xx.xx.xx/BP3_0_32/ru/hs/testservis/somemethod"
NSLog("connection string \(urlPath)")
var url: NSURL = NSURL(string: urlPath)
var request = NSMutableURLRequest(URL: url)
let username = "hs"
let password = "1"
let loginString = NSString(format: "%@:%@", username, password)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)
let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.fromMask(0))
request.setValue(base64LoginString, forHTTPHeaderField: "Authorization")
        

var connection: NSURLConnection = NSURLConnection(request: request, delegate: self)
        

connection.start()
}
    

    

//NSURLConnection delegate method
func connection(connection: NSURLConnection!, didFailWithError error: NSError!) {
println("Failed with error:\(error.localizedDescription)")
}
    

//NSURLConnection delegate method
func connection(didReceiveResponse: NSURLConnection!, didReceiveResponse response: NSURLResponse!) {
//New request so we need to clear the data object
self.data = NSMutableData()
}
    

//NSURLConnection delegate method
func connection(connection: NSURLConnection!, didReceiveData data: NSData!) {
//Append incoming data
self.data.appendData(data)
}
    

//NSURLConnection delegate method
func connectionDidFinishLoading(connection: NSURLConnection!) {
NSLog("connectionDidFinishLoading");
}
    

}
127284 次浏览

URLRequest实例中提供凭据,如 Swift 3中所示:

let username = "user"
let password = "pass"
let loginString = String(format: "%@:%@", username, password)
let loginData = loginString.data(using: String.Encoding.utf8)!
let base64LoginString = loginData.base64EncodedString()


// create the request
let url = URL(string: "http://www.example.com/")!
var request = URLRequest(url: url)
request.httpMethod = "POST"
request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")


// fire off the request
// make sure your class conforms to NSURLConnectionDelegate
let urlConnection = NSURLConnection(request: request, delegate: self)

或者在《雨燕2》中的 NSMutableURLRequest中:

// set up the base64-encoded credentials
let username = "user"
let password = "pass"
let loginString = NSString(format: "%@:%@", username, password)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
let base64LoginString = loginData.base64EncodedStringWithOptions([])


// create the request
let url = NSURL(string: "http://www.example.com/")
let request = NSMutableURLRequest(URL: url)
request.HTTPMethod = "POST"
request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")


// fire off the request
// make sure your class conforms to NSURLConnectionDelegate
let urlConnection = NSURLConnection(request: request, delegate: self)

我的解决方案如下:

import UIKit




class LoginViewController: UIViewController, NSURLConnectionDataDelegate {


@IBOutlet var usernameTextField: UITextField
@IBOutlet var passwordTextField: UITextField


@IBAction func login(sender: AnyObject) {
var url = NSURL(string: "YOUR_URL")
var request = NSURLRequest(URL: url)
var connection = NSURLConnection(request: request, delegate: self, startImmediately: true)


}


func connection(connection:NSURLConnection!, willSendRequestForAuthenticationChallenge challenge:NSURLAuthenticationChallenge!) {


if challenge.previousFailureCount > 1 {


} else {
let creds = NSURLCredential(user: usernameTextField.text, password: passwordTextField.text, persistence: NSURLCredentialPersistence.None)
challenge.sender.useCredential(creds, forAuthenticationChallenge: challenge)


}


}


func connection(connection:NSURLConnection!, didReceiveResponse response: NSURLResponse) {
let status = (response as NSHTTPURLResponse).statusCode
println("status code is \(status)")
// 200? Yeah authentication was successful
}




override func viewDidLoad() {
super.viewDidLoad()


}


override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()


}
}

您可以将此类用作 ViewController 的实现。将字段连接到 IBOutlet 注释变量,将 Button 连接到 IBAction 注释函数。

说明: 在函数登录中,您使用 NSURL、 NSULRequest 和 NSULConnection 创建请求。 这里的关键是引用这个类(self)的委托。 为了接收委托调用,您需要

  • Add the protocol NSURLConnectionDataDelegate to the class
  • 实现协议的“连接: will SendRequestForAuthenticationChallenge”功能 这用于将凭据添加到请求中
  • Implement the protocols' function "connection:didReceiveResponse" This will check the http response status code

I am calling the json on login button click

@IBAction func loginClicked(sender : AnyObject){


var request = NSMutableURLRequest(URL: NSURL(string: kLoginURL)) // Here, kLogin contains the Login API.




var session = NSURLSession.sharedSession()


request.HTTPMethod = "POST"


var err: NSError?
request.HTTPBody = NSJSONSerialization.dataWithJSONObject(self.criteriaDic(), options: nil, error: &err) // This Line fills the web service with required parameters.
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")


var task = session.dataTaskWithRequest(request, completionHandler: {data, response, error -> Void in
//   println("Response: \(response)")
var strData = NSString(data: data, encoding: NSUTF8StringEncoding)
println("Body: \(strData)")
var err1: NSError?
var json2 = NSJSONSerialization.JSONObjectWithData(strData.dataUsingEncoding(NSUTF8StringEncoding), options: .MutableLeaves, error:&err1 ) as NSDictionary


println("json2 :\(json2)")


if(err) {
println(err!.localizedDescription)
}
else {
var success = json2["success"] as? Int
println("Succes: \(success)")
}
})


task.resume()


}

在这里,我为参数编写了一个单独的字典。

var params = ["format":"json", "MobileType":"IOS","MIN":"f8d16d98ad12acdbbe1de647414495ec","UserName":emailTxtField.text,"PWD":passwordTxtField.text,"SigninVia":"SH"]as NSDictionary
return params
}

//创建基于64编码的身份验证字符串

    let PasswordString = "\(txtUserName.text):\(txtPassword.text)"
let PasswordData = PasswordString.dataUsingEncoding(NSUTF8StringEncoding)
let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
//let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(nil)

//创建身份验证 URL

    let urlPath: String = "http://...../auth"
var url: NSURL = NSURL(string: urlPath)

//创建并初始化基本身份验证请求

    var request: NSMutableURLRequest = NSMutableURLRequest(URL: url)
request.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
request.HTTPMethod = "GET"

//您可以使用下列方法之一

//1使用 NSULConnectionDataGenerate 的 URL 请求

    let queue:NSOperationQueue = NSOperationQueue()
let urlConnection = NSURLConnection(request: request, delegate: self)
urlConnection.start()

//2异步请求的 URL 请求

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {(response, data, error) in
println(NSString(data: data, encoding: NSUTF8StringEncoding))
}

//2 URL Request with AsynousRequest with json output//2带有 Json 输出的异步请求的 URL 请求

    NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue(), completionHandler:{ (response: NSURLResponse!, data: NSData!, error: NSError!) -> Void in
var err: NSError
var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(data, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
println("\(jsonResult)")
})

//3使用 SynchronousRequest 的 URL 请求

    var response: AutoreleasingUnsafePointer<NSURLResponse?>=nil
var dataVal: NSData =  NSURLConnection.sendSynchronousRequest(request, returningResponse: response, error:nil)
var err: NSError
var jsonResult: NSDictionary = NSJSONSerialization.JSONObjectWithData(dataVal, options: NSJSONReadingOptions.MutableContainers, error: nil) as NSDictionary
println("\(jsonResult)")

//4通过 NSULSession 请求网址

    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
let authString = "Basic \(base64EncodedCredential)"
config.HTTPAdditionalHeaders = ["Authorization" : authString]
let session = NSURLSession(configuration: config)


session.dataTaskWithURL(url) {
(let data, let response, let error) in
if let httpResponse = response as? NSHTTPURLResponse {
let dataString = NSString(data: data, encoding: NSUTF8StringEncoding)
println(dataString)
}
}.resume()

//如果在服务器请求 GET 请求时更改 request.HTTPMethod = “ POST”,则可能会得到致命错误

In Swift 2:

extension NSMutableURLRequest {
func setAuthorizationHeader(username username: String, password: String) -> Bool {
guard let data = "\(username):\(password)".dataUsingEncoding(NSUTF8StringEncoding) else { return false }


let base64 = data.base64EncodedStringWithOptions([])
setValue("Basic \(base64)", forHTTPHeaderField: "Authorization")
return true
}
}

我有一个类似的问题,试图邮寄到 MailGun 的一些自动电子邮件,我是在一个应用程序实现。

我能够通过一个大的 HTTP 响应使其正常工作。我将完整路径放入 Keys.plist,这样我就可以将代码上传到 github,并将一些参数分解成变量,这样以后就可以通过编程方式设置它们。

// Email the FBO with desired information
// Parse our Keys.plist so we can use our path
var keys: NSDictionary?


if let path = NSBundle.mainBundle().pathForResource("Keys", ofType: "plist") {
keys = NSDictionary(contentsOfFile: path)
}


if let dict = keys {
// variablize our https path with API key, recipient and message text
let mailgunAPIPath = dict["mailgunAPIPath"] as? String
let emailRecipient = "bar@foo.com"
let emailMessage = "Testing%20email%20sender%20variables"


// Create a session and fill it with our request
let session = NSURLSession.sharedSession()
let request = NSMutableURLRequest(URL: NSURL(string: mailgunAPIPath! + "from=FBOGo%20Reservation%20%3Cscheduler@<my domain>.com%3E&to=reservations@<my domain>.com&to=\(emailRecipient)&subject=A%20New%20Reservation%21&text=\(emailMessage)")!)


// POST and report back with any errors and response codes
request.HTTPMethod = "POST"
let task = session.dataTaskWithRequest(request, completionHandler: {(data, response, error) in
if let error = error {
print(error)
}


if let response = response {
print("url = \(response.URL!)")
print("response = \(response)")
let httpResponse = response as! NSHTTPURLResponse
print("response code = \(httpResponse.statusCode)")
}
})
task.resume()
}

Mailgun Path 在 Keys.plist 中是一个名为 mailgunAPIPath 的字符串,其值为:

https://API:key-<my key>@api.mailgun.net/v3/<my domain>.com/messages?

希望这有助于提供一个解决方案,有人试图避免使用第三方代码为他们的 POST 请求!

使用 SWIFT 3和 APACHE 简单版 Auth:

func urlSession(_ session: URLSession, task: URLSessionTask,
didReceive challenge: URLAuthenticationChallenge,
completionHandler: @escaping (URLSession.AuthChallengeDisposition, URLCredential?) -> Void) {


let credential = URLCredential(user: "test",
password: "test",
persistence: .none)


completionHandler(.useCredential, credential)




}

迅速4:

let username = "username"
let password = "password"
let loginString = "\(username):\(password)"


guard let loginData = loginString.data(using: String.Encoding.utf8) else {
return
}
let base64LoginString = loginData.base64EncodedString()


request.httpMethod = "GET"
request.setValue("Basic \(base64LoginString)", forHTTPHeaderField: "Authorization")

SwiftUI iOS15的异步/等待工作示例

   struct ExampleJSONService {
        

let passwordString = "user:password"
let configuration = URLSessionConfiguration.default
        

enum ExampleJSONServiceError: Error {
case failed
case failedToDecode
case invalidStatusCode
}
        

func fetchStuff(for myID:String) async throws -> [Stuff] {
            

let passwordData = passwordString.data(using:String.Encoding.utf8)!
let base64EncodedCredential = passwordData.base64EncodedString()
let authString = "Basic \(base64EncodedCredential)"
let session = URLSession(configuration: configuration)
            

configuration.httpAdditionalHeaders = ["Authorization" : authString]
            

let dataUrl = "https://toto.org/stuff/\(myID)/data.json"
            

let url = URL(string: dataUrl)!
            

var urlRequest = URLRequest(url: url)
            

urlRequest.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
urlRequest.httpMethod = "GET"
            

let (data, response) = try await session.data(for: urlRequest)
            

guard let response = response as? HTTPURLResponse,
    

response.statusCode == 200  else  {
throw PrixJSONServiceError.invalidStatusCode
}
            

let decodedData = try JSONDecoder().decode([Prix].self, from: data)
    

return decodedData
}
        

}