Как сделать HTTP-запрос + basic auth в Swift
У меня есть 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");
}
}
8 ответов:
вы предоставляете учетные данные в
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)
или
NSMutableURLRequest
в 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)
/ / create authentication base 64 encoding string
let PasswordString = "\(txtUserName.text):\(txtPassword.text)" let PasswordData = PasswordString.dataUsingEncoding(NSUTF8StringEncoding) let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength) //let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(nil)
/ / создать url аутентификации
let urlPath: String = "http://...../auth" var url: NSURL = NSURL(string: urlPath)
/ / создание и инициализация запроса на обычную проверку подлинности
var request: NSMutableURLRequest = NSMutableURLRequest(URL: url) request.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization") request.HTTPMethod = "GET"
//вы можете использовать один из следующих способов
//1 URL запрос с NSURLConnectionDataDelegate
let queue:NSOperationQueue = NSOperationQueue() let urlConnection = NSURLConnection(request: request, delegate: self) urlConnection.start()
//2 URL-запрос с AsynchronousRequest
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {(response, data, error) in println(NSString(data: data, encoding: NSUTF8StringEncoding)) }
//2 URL-запрос с асинхронным запросом с выходом 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 URL-запрос с 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 URL запрос с 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()
// вы можете получить фатальную ошибку, если вы изменили запрос.HTTPMethod = "POST" при запросе сервера GET request
В 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 } }
go plain для SWIFT 3 и 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) }
мое решение работает следующим образом:
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. Подключите свои поля к аннотированным vars IBOutlet и кнопку К аннотированной функции IBAction.
объяснение: В функции login вы создаете свой запрос с помощью NSURL, NSURLRequest и NSURLConnection. Существенным здесь является делегат, который ссылается на этот класс (самовыдвижение). Для приема звонков делегатов вам необходимо к
- добавьте протокол NSURLConnectionDataDelegate в класс
- реализовать функцию протоколов " соединение: willSendRequestForAuthenticationchallenge" Это используется для добавления учетных данных в запрос
- реализовать функцию протоколов " соединение:didReceiveResponse" Это проверит код состояния ответа http
Я звоню в 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. Я положил полный путь в Ключи.plist, чтобы я мог загрузить свой код в github и разбил некоторые аргументы на переменные, чтобы я мог их программно установить позже.
// 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 находится в Ключах.plist как строка, называемая mailgunAPIPath с помощью значение:
https://API:key-<my key>@api.mailgun.net/v3/<my domain>.com/messages?
надеюсь, что это помогает предлагает решение для тех, кто пытается избежать использования стороннего кода для своих почтовых запросов!
swift 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")