У меня есть служба 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");
}
}
NSURLConnection(request: request, delegate: self)
будетstart
связь для вас. Не вызывайтеstart
метод явно самостоятельно, эффективно запускайте его во второй раз.Ответы:
Вы предоставляете учетные данные в
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)
источник
NSDataBase64EncodingOptions(0)
илиnil
без опций. Обновил ответ.// создаем строку кодировки базы 64 аутентификации
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-запроса с AsynchronousRequest с выводом 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 запрос
источник
NSURLConnection(request: request, delegate: self)
запускает запрос.start
Второй раз не стоит.быстрый 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")
источник
В 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 } }
источник
перейти на 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) }
источник
У меня была аналогичная проблема с POST-отправкой в MailGun для некоторых автоматических писем, которые я реализовывал в приложении.
Я смог заставить это работать правильно с большим HTTP-ответом. Я поместил полный путь в Keys.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 находится в Keys.plist в виде строки mailgunAPIPath со значением:
https://API:key-<my key>@api.mailgun.net/v3/<my domain>.com/messages?
Надеюсь, это поможет предложить решение тем, кто пытается избежать использования стороннего кода для своих запросов POST!
источник
мое решение работает следующим образом:
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, а вашу кнопку - к аннотированной функции IBAction.
Объяснение: В функции login вы создаете свой запрос с NSURL, NSURLRequest и NSURLConnection. Здесь важен делегат, который ссылается на этот класс (себя). Для приема звонков делегатов необходимо:
источник
Я вызываю 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 }
источник