Cómo hacer una solicitud HTTP + autenticación básica en Swift

Tengo un servicio REST Full con autenticación básica y deseo invocarlo desde iOS + swift. ¿Cómo y dónde debo proporcionar la credencial para esta solicitud?

Mi código (lo siento, solo empiezo a aprender 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"); } 

}

Proporciona credenciales en una instancia de URLRequest , como esta en 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) 

O en NSMutableURLRequest en Swift 2:

 // 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) 

// crear la cadena de encoding de la base de autenticación 64

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

// crear URL de autenticación

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

// crear e inicializar la solicitud de autenticación básica

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

// Puedes usar uno de los siguientes métodos

// 1 solicitud de URL con NSURLConnectionDataDelegate

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

// 2 Solicitud de URL con AsynchronousRequest

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

// 2 Solicitud de URL con AsynchronousRequest con salida json

  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 Solicitud de URL con SynchronousRequest

  var response: AutoreleasingUnsafePointer=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 Solicitud de URL con NSURLSession

  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() 

// puede recibir un error fatal si cambió la solicitud.HTTPMethod = “POST” cuando el servidor solicitó la solicitud GET

En 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 } } 

ve claro para SWIFT 3 y APACHE simple 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) } 

mi solución funciona de la siguiente manera:

 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() } } 

Puede usar esta clase como la implementación de un ViewController. Conecte sus campos a los vars anotados IBOutlet y su botón a la función anotada IBAction.

Explicación: En el inicio de sesión de funciones, crea su solicitud con NSURL, NSURLRequest y NSURLConnection. Esencial aquí es el delegado que hace referencia a esta clase (uno mismo). Para recibir las llamadas de los delegates, necesita

  • Agregue el protocolo NSURLConnectionDataDelegate a la clase
  • Implemente la conexión de la función de los protocolos: willSendRequestForAuthenticationChallenge “Esto se usa para agregar las credenciales a la solicitud
  • Implementar la función de los protocolos “conexión: didReceiveResponse” Esto verificará el código de estado de respuesta http

Llamaré a json al hacer clic en el botón de inicio de sesión

 @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() } 

Aquí, he hecho un diccionario separado para los parámetros.

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

Tuve un problema similar al intentar enviar a MailGun para algunos correos electrónicos automáticos que estaba implementando en una aplicación.

Pude hacer que esto funcionara correctamente con una gran respuesta HTTP. Puse la ruta completa en Keys.plist para que pueda subir mi código a github y descomponer algunos de los argumentos en variables para que pueda progtwigrlos más adelante en el futuro.

 // 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@.com%3E&to=reservations@.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() } 

La ruta de Mailgun está en Keys.plist como una cadena llamada mailgunAPIPath con el valor:

 https://API:key-@api.mailgun.net/v3/.com/messages? 

Espero que esto ayude a ofrecer una solución a alguien que intenta evitar el uso de código de terceros para sus solicitudes de POST.

veloz 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")