Swift'de HTTP isteği + temel kimlik doğrulama nasıl yapılır


100

Temel kimlik doğrulamalı bir RESTFull hizmetim var ve onu iOS + swift'ten çağırmak istiyorum. Bu istek için Kimlik Bilgisini nasıl ve nerede sağlamalıyım?

Kodum (üzgünüm, iOS / obj-c / swift öğrenmeye yeni başlıyorum):

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");
}

}


BTW, sizin için bağlantı NSURLConnection(request: request, delegate: self)yapacak start. startYöntemi açıkça kendiniz çağırmayın , onu ikinci kez etkin bir şekilde başlatın.
Rob

3
NSURLConnection kullanımdan kaldırıldı. Gerçekten NSURLSession'a geçmelisiniz.
Sam Soffes

Yanıtlar:


172

URLRequestSwift 3'te olduğu gibi bir örnekte kimlik bilgileri sağlarsınız:

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)

Veya NSMutableURLRequestSwift 2'de:

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

request.setValue (base64LoginString, forHTTPHeaderField: "Authorization") => request.setValue ("Basic (base64LoginString)", forHTTPHeaderField: "Authorization") "Basic" kelimesini ekledim ve benim için iyi çalışıyor
MrKos

1
İyi yakalama! Cevap güncellendi.
Nate Cook

4
'NSDataBase64EncodingOptions.Type', 'fromMask' adında bir üyeye sahip değil .. Bu, Xcode 6.1..Pls help..What is mask (0)
Bala Vishnu

2
Ayrıca xCode'da @BalaVishnu ile aynı mesajı görüyorum ama bunun yerine .allZeros kullandım
Sean Larkin

1
Swift'in seçenek kümeleri için sözdizimi Xcode 1.1'de değiştirildi. Sen kullanabilirsiniz NSDataBase64EncodingOptions(0)veya nilhiçbir seçenekleri için. Cevap güncellendi.
Nate Cook

22

// kimlik doğrulama tabanı 64 kodlama dizesi oluştur

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

// kimlik doğrulama url'si oluştur

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

// temel kimlik doğrulama isteği oluştur ve başlat

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

// Aşağıdaki yöntemlerden birini kullanabilirsiniz

// NSURLConnectionDataDelegate ile 1 URL isteği

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

// AsynchronousRequest ile 2 URL İsteği

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

// json çıktılı AsynchronousRequest ile 2 URL İsteği

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

// SynchronousRequest ile 3 URL İsteği

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

// NSURLSession ile 4 URL İsteği

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

// sunucu isteği GET isteği olduğunda request.HTTPMethod = "POST" değerini değiştirdiyseniz ölümcül bir hata alabilirsiniz


2
BTW, bu OP'nin kodundaki hatayı tekrarlar: NSURLConnection(request: request, delegate: self)talebi başlatır. Bunu startikinci kez yapmamalısın .
Rob

19

hızlı 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")

6

Swift 2'de:

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


4

SWIFT 3 ve APACHE basit Kimlik Doğrulama için düz gidin:

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)


}

2

Bir uygulamada uyguladığım bazı otomatik e-postalar için MailGun'a POST yapmaya çalışırken benzer bir sorun yaşadım.

Bunun büyük bir HTTP yanıtıyla düzgün çalışmasını sağlayabildim. Kodumu github'a yükleyebilmek için tam yolu Keys.plist'e koydum ve bazı argümanları değişkenlere ayırdım, böylece onları daha sonra programlı olarak ayarlayabileyim.

// 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 Yolu, aşağıdaki değere sahip mailgunAPIPath adlı bir dize olarak Keys.plist'te bulunur:

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

Umarım bu, POST istekleri için 3. taraf kodunu kullanmaktan kaçınmaya çalışan birine bir çözüm sunar!


1

benim çözümüm şu şekilde çalışıyor:

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

  }  
}

Bu sınıfı bir ViewController uygulaması olarak kullanabilirsiniz. Alanlarınızı IBOutlet açıklamalı değişkenlerine ve Düğmenizi IBAction açıklamalı işleve bağlayın.

Açıklama: Oturum açma işlevinde isteğinizi NSURL, NSURLRequest ve NSURLConnection ile oluşturursunuz. Burada önemli olan, bu sınıfa (kendine) atıfta bulunan temsilcidir. Temsilci çağrılarını almak için yapmanız gerekenler

  • NSURLConnectionDataDelegate protokolünü sınıfa ekleyin
  • Protokollerin "bağlantı: willSendRequestForAuthenticationChallenge" işlevini uygulayın Bu, isteğe kimlik bilgilerini eklemek için kullanılır
  • Protokollerin "bağlantı: didReceiveResponse" işlevini uygulayın. Bu, http yanıt durum kodunu kontrol edecektir

Eşzamanlı bir istek için http yanıt durum kodunu kontrol etmenin bir yolu var mı?
Matt

NSURLConnection kullanımdan kaldırıldı. Apple, NSURLSession'ı kullanmanızı şiddetle tavsiye eder.
Sam Soffes

1

Oturum açma düğmesi tıklandığında json'ı arıyorum

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

}

Burada parametreler için ayrı bir sözlük yaptım.

var params = ["format":"json", "MobileType":"IOS","MIN":"f8d16d98ad12acdbbe1de647414495ec","UserName":emailTxtField.text,"PWD":passwordTxtField.text,"SigninVia":"SH"]as NSDictionary
     return params
}
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.