Cách tạo yêu cầu HTTP + xác thực cơ bản trong Swift


96

Tôi có dịch vụ RESTFull với xác thực cơ bản và tôi muốn gọi nó từ iOS + nhanh chóng. Tôi phải cung cấp Thông tin đăng nhập cho yêu cầu này như thế nào và ở đâu?

Mã của tôi (xin lỗi, tôi mới bắt đầu học 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");
}

}


BTW, NSURLConnection(request: request, delegate: self)sẽ startkết nối cho bạn. Đừng tự gọi startphương thức một cách rõ ràng, hãy bắt đầu nó một cách hiệu quả lần thứ hai.
Rob

3
NSURLConnection không được dùng nữa. Bạn thực sự nên chuyển sang NSURLSession.
Sam Soffes

Câu trả lời:


168

Bạn cung cấp thông tin xác thực trong một URLRequeství dụ, như thế này trong 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)

Hoặc trong 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)

request.setValue (base64LoginString, forHTTPHeaderField: "Authorization") => request.setValue ( "Basic (base64LoginString)", forHTTPHeaderField: "Authorization") từ tôi đã thêm "cơ bản" và nó làm việc cho tôi cũng
MrKos

1
Nắm bắt tốt! Đã cập nhật câu trả lời.
Nate Cook

4
'NSDataBase64EncodingOptions.Type' không có thành viên có tên 'fromMask' .. Đây là lỗi tôi gặp phải trong Xcode 6.1. Xin hãy giúp đỡ..Mặt nạ là gì (0)
Bala Vishnu

2
Tôi cũng thấy thông báo tương tự như @BalaVishnu trong xCode nhưng tôi chỉ sử dụng .allZeros để thay thế
Sean Larkin

1
Cú pháp của Swift cho các bộ tùy chọn đã thay đổi trong Xcode 1.1. Bạn có thể sử dụng NSDataBase64EncodingOptions(0)hoặc nilkhông tùy chọn. Đã cập nhật câu trả lời.
Nate Cook

22

// tạo chuỗi mã hóa cơ sở xác thực 64

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

// tạo url xác thực

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

// tạo và khởi tạo yêu cầu xác thực cơ bản

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

// Bạn có thể sử dụng một trong các phương pháp dưới đây

// 1 yêu cầu URL với NSURLConnectionDataDelegate

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

// 2 Yêu cầu URL với AsynchronousRequest

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

// 2 Yêu cầu URL với AsynchronousRequest với đầu ra 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 Yêu cầu URL với 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 Yêu cầu URL với 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()

// bạn có thể gặp lỗi nghiêm trọng nếu bạn thay đổi yêu cầu.HTTPMethod = "POST" khi máy chủ yêu cầu GET request


2
BTW, điều này lặp lại lỗi trong mã OP: NSURLConnection(request: request, delegate: self)bắt đầu yêu cầu. Bạn không nên startnó lần thứ hai.
Rob

18

nhanh chóng 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

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

Tôi không chắc chắn nếu bạn cần phải thoát khỏi bất cứ điều gì trước khi chuyển đổi nó sang base64
Sam Soffes

3

đơn giản cho SWIFT 3 và APACHE Auth đơn giản:

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

Tôi đã gặp sự cố tương tự khi cố ĐĂNG lên MailGun cho một số email tự động mà tôi đang triển khai trong một ứng dụng.

Tôi đã có thể làm cho điều này hoạt động bình thường với một phản hồi HTTP lớn. Tôi đặt đường dẫn đầy đủ vào Keys.plist để có thể tải mã của mình lên github và chia nhỏ một số đối số thành các biến để tôi có thể đặt chúng theo chương trình sau này.

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

Đường dẫn Mailgun nằm trong Keys.plist dưới dạng một chuỗi được gọi là mailgunAPIPath với giá trị:

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

Hy vọng điều này sẽ giúp đưa ra giải pháp cho ai đó đang cố gắng tránh sử dụng mã của bên thứ 3 cho các yêu cầu ĐĂNG của họ!


1

giải pháp của tôi hoạt động như sau:

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

  }  
}

Bạn có thể sử dụng lớp này như việc triển khai một ViewController. Kết nối các trường của bạn với các vars được chú thích IBOutlet và Nút của bạn với chức năng được chú thích của IBAction.

Giải thích: Trong đăng nhập chức năng, bạn tạo yêu cầu của mình bằng NSURL, NSURLRequest và NSURLConnection. Essential ở đây là đại biểu tham chiếu đến lớp này (bản thân). Để nhận các cuộc gọi của đại biểu, bạn cần

  • Thêm giao thức NSURLConnectionDataDelegate vào lớp
  • Triển khai chức năng của giao thức "kết nối: willSendRequestForAuthenticationChallenge" Điều này được sử dụng để thêm thông tin xác thực vào yêu cầu
  • Triển khai chức năng của giao thức "kết nối: didReceiveResponse" Điều này sẽ kiểm tra mã trạng thái phản hồi http

Có cách nào để kiểm tra mã trạng thái phản hồi http cho một yêu cầu đồng bộ không?
Matt

NSURLConnection không được dùng nữa. Apple đặc biệt khuyến khích bạn sử dụng NSURLSession.
Sam Soffes

1

Tôi đang gọi json khi nhấp vào nút đăng nhập

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

}

Ở đây, tôi đã tạo một từ điển riêng cho các tham số.

var params = ["format":"json", "MobileType":"IOS","MIN":"f8d16d98ad12acdbbe1de647414495ec","UserName":emailTxtField.text,"PWD":passwordTxtField.text,"SigninVia":"SH"]as NSDictionary
     return params
}
Khi sử dụng trang web của chúng tôi, bạn xác nhận rằng bạn đã đọc và hiểu Chính sách cookieChính sách bảo mật của chúng tôi.
Licensed under cc by-sa 3.0 with attribution required.