Mam usługę RESTFull z podstawowym uwierzytelnianiem i chcę ją wywołać z iOS + swift. Jak i gdzie muszę podać poświadczenia dla tego żądania?
Mój kod (przepraszam, dopiero zaczynam się uczyć 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)
będziestart
połączenie dla Ciebie. Nie wywołujstart
metody jawnie samodzielnie, skutecznie uruchamiając ją po raz drugi.Odpowiedzi:
Podajesz poświadczenia w
URLRequest
instancji, na przykład w 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)
Lub w
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)
źródło
NSDataBase64EncodingOptions(0)
lubnil
bez opcji. Zaktualizowałem odpowiedź.// utwórz ciąg kodowania uwierzytelniania bazowego 64
let PasswordString = "\(txtUserName.text):\(txtPassword.text)" let PasswordData = PasswordString.dataUsingEncoding(NSUTF8StringEncoding) let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength) //let base64EncodedCredential = PasswordData!.base64EncodedStringWithOptions(nil)
// utwórz adres URL uwierzytelniania
let urlPath: String = "http://...../auth" var url: NSURL = NSURL(string: urlPath)
// tworzy i inicjuje podstawowe żądanie uwierzytelnienia
var request: NSMutableURLRequest = NSMutableURLRequest(URL: url) request.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization") request.HTTPMethod = "GET"
// Możesz użyć jednej z poniższych metod
// 1 żądanie adresu URL z NSURLConnectionDataDelegate
let queue:NSOperationQueue = NSOperationQueue() let urlConnection = NSURLConnection(request: request, delegate: self) urlConnection.start()
// 2 Żądanie adresu URL z AsynchronousRequest
NSURLConnection.sendAsynchronousRequest(request, queue: NSOperationQueue.mainQueue()) {(response, data, error) in println(NSString(data: data, encoding: NSUTF8StringEncoding)) }
// 2 Żądanie adresu URL z AsynchronousRequest z wyjściem 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 żądanie adresu URL z 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 Żądanie adresu URL z sesją NSURL
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()
// możesz otrzymać błąd krytyczny, jeśli zmienisz żądanie.HTTPMethod = "POST", gdy serwer zażąda żądania GET
źródło
NSURLConnection(request: request, delegate: self)
uruchamia żądanie. Nie powinieneśstart
tego robić po raz drugi.szybki 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")
źródło
W 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 } }
źródło
proste dla SWIFT 3 i 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) }
źródło
Miałem podobny problem podczas próby wysłania POST do MailGun dla niektórych automatycznych e-maili, które implementowałem w aplikacji.
Udało mi się to poprawnie działać z dużą odpowiedzią HTTP. Umieściłem pełną ścieżkę w Keys.plist, aby móc przesłać swój kod na github i podzielić niektóre argumenty na zmienne, aby móc je programowo ustawić później.
// 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 = "[email protected]" 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() }
Ścieżka Mailgun znajduje się w Keys.plist jako ciąg o nazwie mailgunAPIPath i ma wartość:
https://API:key-<my key>@api.mailgun.net/v3/<my domain>.com/messages?
Mam nadzieję, że pomoże to zaoferować rozwiązanie dla kogoś, kto próbuje uniknąć używania kodu innej firmy w swoich żądaniach POST!
źródło
moje rozwiązanie działa w następujący sposób:
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() } }
Możesz użyć tej klasy jako implementacji ViewController. Połącz swoje pola ze zmiennymi z adnotacjami IBOutlet, a Twój Button z funkcją z adnotacjami IBAction.
Objaśnienie: W funkcji logowania tworzysz żądanie za pomocą nazw NSURL, NSURLRequest i NSURLConnection. Istotny jest tutaj delegat, który odwołuje się do tej klasy (self). Aby odbierać telefony od delegatów, musisz
źródło
Wzywam json po kliknięciu przycisku logowania
@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() }
Tutaj stworzyłem osobny słownik dla parametrów.
var params = ["format":"json", "MobileType":"IOS","MIN":"f8d16d98ad12acdbbe1de647414495ec","UserName":emailTxtField.text,"PWD":passwordTxtField.text,"SigninVia":"SH"]as NSDictionary return params }
źródło