Cara membuat permintaan HTTP + autentikasi dasar di Swift

99

Saya memiliki layanan RESTFull dengan otentikasi dasar dan saya ingin memanggilnya dari iOS + swift. Bagaimana dan di mana saya harus memberikan Kredensial untuk permintaan ini?

Kode saya (maaf, saya baru mulai belajar 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");
}

}

MrKos
sumber
BTW, NSURLConnection(request: request, delegate: self)akan startkoneksi untuk Anda. Jangan menyebut startmetode sendiri secara eksplisit, secara efektif memulainya untuk kedua kalinya.
Rob
3
NSURLConnection tidak digunakan lagi. Anda harus benar-benar beralih ke NSURLSession.
Sam Soffes

Jawaban:

171

Anda memberikan kredensial dalam sebuah URLRequestinstance, seperti ini di 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)

Atau di NSMutableURLRequestSwift 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)
Nate Cook
sumber
request.setValue (base64LoginString, forHTTPHeaderField: "Authorization") => request.setValue ("Basic (base64LoginString)", forHTTPHeaderField: "Authorization") saya telah menambahkan kata "Basic" dan itu bekerja dengan baik untuk saya
MrKos
1
Tangkapan yang bagus! Memperbarui jawabannya.
Nate Cook
4
'NSDataBase64EncodingOptions.Type' tidak memiliki anggota bernama 'fromMask' .. Ini adalah kesalahan yang saya dapatkan di Xcode 6.1..Pls help..Apa itu mask (0)
Bala Wisnu
2
Saya juga melihat pesan yang sama dengan @BalaVishnu di xCode tetapi saya hanya menggunakan .allZeros sebagai gantinya
Sean Larkin
1
Sintaks Swift untuk kumpulan opsi diubah di Xcode 1.1. Anda dapat menggunakan NSDataBase64EncodingOptions(0)atau niltanpa opsi. Memperbarui jawabannya.
Nate Cook
22

// buat string encoding basis 64 otentikasi

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

// buat url otentikasi

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

// buat dan inisialisasi permintaan otentikasi dasar

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

// Anda dapat menggunakan salah satu metode di bawah ini

// 1 permintaan URL dengan NSURLConnectionDataDelegate

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

// 2 Permintaan URL dengan AsynchronousRequest

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

// 2 Permintaan URL dengan AsynchronousRequest dengan keluaran 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 Permintaan URL dengan SynchronousRequest

    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 Permintaan URL dengan 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()

// Anda mungkin mendapatkan kesalahan fatal jika Anda mengubah permintaan.HTTPMethod = "POST" ketika server meminta permintaan GET

Subhash
sumber
2
BTW, ini mengulangi kesalahan dalam kode OP: NSURLConnection(request: request, delegate: self)memulai permintaan. Anda seharusnya tidak startmelakukannya untuk kedua kalinya.
Rob
19

cepat 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")
Amr
sumber
6

Di 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
    }
}
Sam Soffes
sumber
Saya tidak yakin apakah Anda perlu melarikan diri sebelum mengubahnya menjadi base64
Sam Soffes
4

gunakan SWIFT 3 dan 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)


}
ingconti
sumber
2

Saya mengalami masalah serupa saat mencoba POST ke MailGun untuk beberapa email otomatis yang saya terapkan di aplikasi.

Saya bisa membuatnya berfungsi dengan baik dengan respons HTTP yang besar. Saya memasukkan jalur lengkap ke Keys.plist sehingga saya dapat mengunggah kode saya ke github dan memecah beberapa argumen menjadi variabel sehingga saya dapat mengaturnya secara terprogram nanti.

// 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 = "[email protected]"
    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()
}

Jalur Mailgun ada di Keys.plist sebagai string yang disebut mailgunAPIPath dengan nilai:

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

Semoga ini bisa membantu menawarkan solusi bagi seseorang yang mencoba menghindari penggunaan kode pihak ketiga untuk permintaan POST mereka!

Budha paling kasar
sumber
1

solusi saya berfungsi sebagai berikut:

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

  }  
}

Anda dapat menggunakan kelas ini sebagai implementasi dari ViewController. Hubungkan bidang Anda ke variabel beranotasi IBOutlet dan Tombol Anda ke fungsi beranotasi IBAction.

Penjelasan: Dalam function login Anda membuat permintaan Anda dengan NSURL, NSURLRequest dan NSURLConnection. Yang penting di sini adalah delegasi yang merujuk ke kelas ini (diri). Anda perlu menerima panggilan delegasi

  • Tambahkan protokol NSURLConnectionDataDelegate ke kelas
  • Menerapkan fungsi protokol "koneksi: willSendRequestForAuthenticationChallenge" Ini digunakan untuk menambahkan kredensial ke permintaan
  • Menerapkan fungsi protokol "koneksi: didReceiveResponse" Ini akan memeriksa kode status tanggapan http
Oliver Koehler
sumber
Apakah ada cara untuk memeriksa kode status tanggapan http untuk permintaan sinkron?
Matt
NSURLConnection tidak digunakan lagi. Apple sangat menganjurkan Anda untuk menggunakan NSURLSession.
Sam Soffes
1

Saya menelepon json pada klik tombol login

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

}

Di sini, saya telah membuat kamus terpisah untuk parameter.

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