如何在Swift中进行HTTP请求+基本身份validation
我有一个基本authentication的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"); }
}
您在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)
或者在Swift 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)
//创buildauthentication库64编码string
let PasswordString = "\(txtUserName.text):\(txtPassword.text)" let PasswordData = PasswordString.dataUsingEncoding(NSUTF8StringEncoding) let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength) //let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(nil)
//创buildauthenticationurl
let urlPath: String = "http://...../auth" var url: NSURL = NSURL(string: urlPath)
//创build并初始化基本authentication请求
var request: NSMutableURLRequest = NSMutableURLRequest(URL: url) request.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization") request.HTTPMethod = "GET"
//你可以使用下面的方法之一
// 1与NSURLConnectionDataDelegate的URL请求
let queue:NSOperationQueue = NSOperationQueue() let urlConnection = NSURLConnection(request: request, delegate: self) urlConnection.start()
// 2与AsynchronousRequest的URL请求
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {(response, data, error) in println(NSString(data: data, encoding: NSUTF8StringEncoding)) }
// 2带有json输出的AsynchronousRequest的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使用NSURLSession的URL请求
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”,则可能会发生致命错误
在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 } }
我的解决scheme如下所示:
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注释的variables和您的button到IBAction注释的函数。
说明:在函数login中,用NSURL,NSURLRequest和NSURLConnection创build请求。 这里的重点是引用这个类的代表(self)。 为了接收你需要的代表电话
- 将协议NSURLConnectionDataDelegate添加到类
- 实现协议的function“连接:willSendRequestForAuthenticationChallenge”这用于将凭据添加到请求
- 实现协议的function“连接:didReceiveResponse”这将检查http响应状态码
我在loginbutton点击调用json
@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 }
我有一个类似的问题,试图邮寄到MailGun的一些自动化的电子邮件,我正在实施一个应用程序。
我能够通过一个大的HTTP响应来正确地工作。 我将完整path放到Keys.plist中,以便我可以将代码上传到github,并将一些参数分解成variables,以便稍后以编程方式设置它们。
// 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() }
Mailgunpath在Keys.plist中是一个名为mailgunAPIPath的string,值为:
https://API:key-<my key>@api.mailgun.net/v3/<my domain>.com/messages?
希望这有助于为尝试避免使用第三方代码进行POST请求的人提供解决scheme!
明白SWIFT 3和APACHE简单的authentication:
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) }