all.
I can get authentication token by login. but I can authenticate on my server by swift and alamofire.
this is Postman. as you see, if i have token, i can be authenticated on myserver.
this is swift viewcontroller.
import UIKit
import Alamofire
import SwiftyJSON
import KeychainAccess
class ViewController: UIViewController {
let authLoginUrl = "http://ec2-52-79-155-29.ap-northeast-2.compute.amazonaws.com:8000/rest-auth/login/"
let keychain = Keychain(service: "wanote")
let projectUrl = "http://ec2-52-79-155-29.ap-northeast-2.compute.amazonaws.com:8000/api/user/ryulstory"
override func viewDidLoad() {
super.viewDidLoad()
// Do any additional setup after loading the view, typically from a nib.
let username = "username"
let password = "1234!"
self.doAuth(username: username, password: password)
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
func doAuth(username:String, password:String) {
let params = ["username": username, "password": password]
var authToken = Alamofire.request(self.authLoginUrl, method: .post, parameters: params)
authToken.responseJSON { response in
let statusCode = response.response?.statusCode ?? 0
switch statusCode {
case 200...299:
let jsonData = JSON(response.result.value)
if let token = jsonData["key"].string{
self.keychain["token"] = token
self.getProjects()
}
case 400...499:
print("Server responded no")
case 500...599:
print("Server error")
default:
print("There was an error with your request")
}
}
}
func getProjects(){
if let token = self.keychain["token"] {
if let Purl = URL(string: self.projectUrl){
var mutableUrlRequest = URLRequest(url: Purl)
mutableUrlRequest.httpMethod = "GET"
mutableUrlRequest.setValue("Token " + token, forHTTPHeaderField: "Authorization")
var manager = Alamofire.SessionManager.default
var getProjectsRequest = manager.request(mutableUrlRequest)
getProjectsRequest.responseJSON { response in
print(response.data)
}
}
} else {
print("no token")
}
}
}
I checked getting token by function doAuth. it is correctly operating.
function getprojects makes error status code 401.
I think there are problem in function getprojects. but i can't find it.
could you help me?
Best regards.
It goes to 401 because you are sending the request without the header authorization.
With Alamofire you can set the header Authorization like this.
let url = "URL_LOGIN"
//Get token logic
let token = ""
let headers = ["Authorization": "Token \(token)"]
let params = ["user": "", "pass":""] //This goes in the body of the request
Alamofire.request(url, method: .post, parameters: params, encoding: URLEncoding.default, headers: headers).responseJSON { (response) in
if let value = response.result.value {
print(value)
}
}
With this you'll send the headers in the request to get what you want.
I think this part have the header authorization.
is it wrong?
mutableUrlRequest.httpMethod = "GET"
mutableUrlRequest.setValue("Token " + token, forHTTPHeaderField: "Authorization")
var manager = Alamofire.SessionManager.default
var getProjectsRequest = manager.request(mutableUrlRequest)
Related
I am setting the basic auth token to my URLRequest and using Alamofire to execute.
I set 3 headers, content, accept and auth...content and accept are visible in the network traffic but auth is not. It is available if i print the headers of the URLRequest before its sent...
Any ideas here? as i dont see how its removing the auth header before posting
Code as follows:
// Construct url
let url = try APIConstants.baseUrl.asURL()
// Append path
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
// Determine HTTP method
urlRequest.httpMethod = method.rawValue
let headers: HTTPHeaders = [
.contentType(APIConstants.ContentType.json.rawValue),
.accept(APIConstants.ContentType.json.rawValue),
]
if let token = token {
urlRequest.addValue("\(APIConstants.API.token.rawValue) \(token.key)",
forHTTPHeaderField: "Authorization")
}
urlRequest.headers = headers
// Add http body to request
if let parameters = parameters {
do {
let data = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
urlRequest.httpBody = data
} catch (_) {
print("APIRouter: Failed to parse body into request.")
}
}
//Encoding
let encoding: ParameterEncoding = {
switch method {
case .get:
return URLEncoding.default
default:
return JSONEncoding.default
}
}()
return try encoding.encode(urlRequest, with: parameters)
}
In my rest client i execute like this:
return Observable<T>.create { observer in
let request = AF.request(urlConvertible).responseDecodable { (response: DataResponse<T, AFError>) in
switch response.result {
case .success(let value):
observer.onNext(value)
observer.onCompleted()
case .failure(let error):
switch response.response?.statusCode {
case 403:
observer.onError(APIError.forbidden)
case 404:
observer.onError(APIError.notFound)
case 409:
observer.onError(APIError.conflict)
case 500:
observer.onError(APIError.internalServerError)
default:
observer.onError(error)
}
}
}
return Disposables.create {
request.cancel()
}
}
}
Edit:
Updated func to show further issue:
func asURLRequest() throws -> URLRequest {
// Construct url
let url = try APIConstants.baseUrl.asURL()
// Append path
var urlRequest = URLRequest(url: url.appendingPathComponent(path))
// Determine HTTP method
urlRequest.httpMethod = method.rawValue
let headers: HTTPHeaders = [
.contentType(APIConstants.ContentType.json.rawValue),
.accept(APIConstants.ContentType.json.rawValue),
.authorization("Token a5555485aa251b28fdsfasdfdsb379c131fddad")
]
urlRequest.headers = headers
// Add http body to request
if let parameters = parameters {
do {
let data = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted)
urlRequest.httpBody = data
} catch (_) {
print("APIRouter: Failed to parse body into request.")
}
}
//Encoding
let encoding: ParameterEncoding = {
switch method {
case .get:
return URLEncoding.default
default:
return JSONEncoding.default
}
}()
return try encoding.encode(urlRequest, with: parameters)
}
After setting the Authorization header in your URLRequest:
urlRequest.addValue("\(APIConstants.API.token.rawValue) \(token.key)", forHTTPHeaderField: "Authorization")
then you override all the request's headers by setting headers property:
urlRequest.headers = headers
A nice solution would be to update the headers that you already created above, like this:
var headers: HTTPHeaders = [
.contentType(APIConstants.ContentType.json.rawValue),
.accept(APIConstants.ContentType.json.rawValue),
]
if let token = token {
headers.add(.authorization("\(APIConstants.API.token.rawValue) \(token.key)"))
}
urlRequest.headers = headers
Another solution is to use KeyValue pair as follows:
var header: HTTPHeaders = [:]
if let token = getValueFromUserDefaults(keyName: "authToken") as? String {
header["Authorization"] = token
}
I always use this method. It's more handy for me.
Here i am sending parameter value like username, user toke, post id, etc to backend using alamofire. if status success then, notification will will send from backend. Inside postnotification function i have tried post method code using alamofire and datatask method but it does not work. In console i am getting request time out or nothing.
Here is my code :
func postNotification(postItem: String, post: Post) {
// declare parameter as a dictionary which contains string as key and value combination. considering inputs are valid
print("Get token from post:::",post.token)
print(postItem)
let token = UserDefaults.standard.string(forKey: "token")
//create the url with URL
var parameters = [String:Any]()
parameters["count"] = post.likeCount!
parameters["likedby"] = currentName
parameters["postId"] = postItem
parameters["token"] = post.token!
let Url = String(format: "http://highavenue.co:9000/likesnotification")
guard let serviceUrl = URL(string: Url) else { return }
// let loginParams = String(format: LOGIN_PARAMETERS1, "test", "Hi World")
let parameterDictionary = ["username" : "Test", "password" : "123456"]
var request = URLRequest(url: serviceUrl)
request.httpMethod = "POST"
request.setValue("Application/json", forHTTPHeaderField: "Content-Type")
guard let httpBody = try? JSONSerialization.data(withJSONObject: parameters, options: []) else {
return
}
request.httpBody = httpBody
let session = URLSession.shared
session.dataTask(with: request) { (data, response, error) in
if let response = response {
print(response)
}
if let data = data {
do {
let json = try JSONSerialization.jsonObject(with: data, options: [])
print(json)
}catch {
print(error)
}
}
}.resume()
// let headers: HTTPHeaders = ["Content-Type" :"application/x-www-form-urlencoded"]
//
// Alamofire.request("http://highavenue.co:9000/likesnotification", method: .post, parameters: parameters, encoding: JSONEncoding.default, headers: headers).responseJSON { (response) in
// // original URL request
// print("Request is :",response.request!)
//
// // HTTP URL response --> header and status code
// print("Response received is :",response.response)
//
// // server data : example 267 bytes
// print("Response data is :",response.data)
//
// // result of response serialization : SUCCESS / FAILURE
// print("Response result is :",response.result)
//
// debugPrint("Debug Print :", response)
//
//
// }
// Alamofire.request("http://highavenue.co:9000/likesnotification", method: HTTPMethod.post, parameters: json, encoding: JSONEncoding.default, headers: headers).responseJSON { response in
//
// // original URL request
// print("Request is :",response.request!)
//
// // HTTP URL response --> header and status code
// print("Response received is :",response.response)
//
// // server data : example 267 bytes
// print("Response data is :",response.data)
//
// // result of response serialization : SUCCESS / FAILURE
// print("Response result is :",response.result)
//
// debugPrint("Debug Print :", response)
// }
}
Any help much appreciated pls..
Yaah solved it. There was a negligence mistake. I used an additional slash in the URL. I changed the web API to a different folder and I made this mistake while changing it in the iOS code. and Also Set your timeout interval here.
let RequestData = NSMutableURLRequest(URL: NSURL.init(string: "Your URL Hear")!)
RequestData.HTTPMethod = "POST"
RequestData.timeoutInterval = 250 // Time interval here.
Alamofire.request(RequestData).responseJSON { (responseData) -> Void in
if((responseData.result.value) != nil) { // response
print(responseData.result.value!)
}
}
Hope this Help You..
These are request headers:
let headers: HTTPHeaders = [
"Accept": "application/json",
"username": "someUserName",
"password": "aPasswordForSomeUserName"
]
When making a request with below code it's giving me "Garbage at the end". However, when I checked the response with JSON parser online. It's a valid JSON.
Alamofire.request("http://myserver/list.svc/random", headers: headers).responseJSON { response in
print(response)
}
I also tried making a request like this:
Alamofire.request("http://myserver/list.svc/random", headers: headers).responseString { response in
print(response)
}
I am getting this message in console: "401 UNAUTHORIZED".
What am I doing wrong? I believe, when using responseJSON completion block it's not complaining about Unauthorization, but it's complaining about bad JSON (or some garbage).
P.S. The same request works fine with Advance Rest Client (a chrome extension) and also in chrome browser.
I don't know how relevant this is to you anymore but I've got a working solution I'll post for any future reference.
So, I had two issues. The first one being that the Authorization header fell of the request when it was redirected. The second one being the NTLM-challenge from the server not being handled. The following code should be quite self explanatory I hope :) It asumes you store the username and password in variables name just that.
let credentialData = "\(username):\(password)".data(using: String.Encoding.utf8)!
let base64Credentials = credentialData.base64EncodedString(options: [])
request.addValue("Basic \(base64Credentials)", forHTTPHeaderField: "Authorization")
let manager = Alamofire.SessionManager.default
let delegate: Alamofire.SessionDelegate = manager.delegate
// This bit will re-add the auth headers for the redirected request
delegate.taskWillPerformHTTPRedirection = { session, task, response, request in
var redirectedRequest = request
if let originalRequest = task.originalRequest, let redirectheaders = originalRequest.allHTTPHeaderFields {
if let authorizationHeaderValue = redirectheaders["Authorization"] {
redirectedRequest.setValue(authorizationHeaderValue, forHTTPHeaderField: "Authorization")
}
if let contentTypeHeaderValue = redirectheaders["Content-Type"] {
redirectedRequest.setValue(contentTypeHeaderValue, forHTTPHeaderField: "Content-Type")
}
}
return redirectedRequest
}
// This bit looks at challenges received and applies the correct credentials
delegate.taskDidReceiveChallenge = { session, task, challenge in
var disposition: URLSession.AuthChallengeDisposition = .useCredential
var credential: URLCredential = URLCredential()
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodNTLM) {
disposition = URLSession.AuthChallengeDisposition.useCredential
credential = URLCredential(user: username, password: password, persistence: URLCredential.Persistence.forSession)
}
if (challenge.protectionSpace.authenticationMethod == NSURLAuthenticationMethodServerTrust) {
disposition = URLSession.AuthChallengeDisposition.useCredential
credential = URLCredential(trust: challenge.protectionSpace.serverTrust!)
}
return(disposition, credential)
}
manager.request(request).responseData { (response) in
// Handle response accordingly
}
Hope this helps someone.
In Swift4.2
Alamofire has built in NTLM auth support.
You can make a request like that
let user = "YOUR_USER_NAME OR EMAIL"
let password = "YOUR_PASSWORD"
let url = "YOUR_API_URL"
let credential = URLCredential(user: user, password: password, persistence: .forSession)
//These headers are optional based on your api and your server.
//There were required for me
let headers = ["Accept": "application/json;odata=verbose",
"Content-type": "application/json;odata=verbose"]
Alamofire.request(url, method: .get, headers: headers).authenticate(usingCredential: credential).responseJSON {
(response) in
switch response.result {
case .success:
if let value = response.result.value {
print("The server response is: ", value)
}else{
print("There is error in the server response")
}
case .failure (let error):
print("The NTLM request error is: ", error.localizedDescription)
}
}
I am building an app that checks domain availability. Right now, I am using the goDaddy API; according to goDaddy, the way to check URL availability is by the following cURL command:
curl -X GET -H "Authorization: sso-key {API_KEY}:{API_SECRET}" "https://api.godaddy.com/v1/domains/available?domain=example.guru"
Right now, I am trying to translate that cURL command to Swift. I am using Alamofire; however, when I make a request, an error as the following shows up:
Credentials must be specified
I was wondering how to solve this problem. Here is my current code:
class ViewController: UIViewController {
let key = "KEYKEYKEY"
let secret = "SECRETSECRET"
var headers: HTTPHeaders = [:]
override func viewDidLoad() {
super.viewDidLoad()
let credential = URLCredential(user: key, password: secret, persistence: .forSession)
Alamofire.request("https://api.godaddy.com/v1/domains/available?domain=example.guru")
.authenticate(usingCredential: credential)
.responseJSON { response in
debugPrint(response)
}
// Do any additional setup after loading the view, typically from a nib.
}
override func didReceiveMemoryWarning() {
super.didReceiveMemoryWarning()
// Dispose of any resources that can be recreated.
}
}
I know that this is not using Alamofire but this is how I would achieve it.
import PlaygroundSupport
import Foundation
let key = "2s7Ymz8gu7_8XuTEeMFVmxJBLmyNNL4n8"
let secret = "8XuXAs8K37ejtYqvsEue2p"
let url = URL(string: "https://api.ote-godaddy.com/v1/domains/available?domain=example.guru&checkType=FULL")
var request = URLRequest(url: url!)
request.addValue("application/json", forHTTPHeaderField: "Accept")
request.addValue("sso-key \(key):\(secret)", forHTTPHeaderField: "Authorization")
let task = URLSession.shared.dataTask(with: request) { data, response, error in
guard error == nil else {
print(error!)
return
}
guard let data = data else {
print("Data is empty")
return
}
let json = try! JSONSerialization.jsonObject(with: data, options: [])
print(json)
}
task.resume()
PlaygroundPage.current.needsIndefiniteExecution = true
I'm trying to add headers into AlamoFire requests.
It works well when I use the following code:
let manager = Manager.sharedInstance
manager.session.configuration.HTTPAdditionalHeaders = [
"Authorization": "Bearer \(accessToken!)" ]
However, when I need to user an ephemeral session it does not work with the following code.
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
let manager = Manager(configuration: configuration)
manager.session.configuration.HTTPAdditionalHeaders = [
"Authorization": "Bearer \(accessToken!)" ]
Am I missing something?
Thanks in advance,
You have to ensure your manager is retained, you could do it by setting it as a stored property. You'll find more informations here: https://github.com/Alamofire/Alamofire/issues/157
let customManager: Manager?
init() {
let configuration = NSURLSessionConfiguration.ephemeralSessionConfiguration()
self.customManager = Manager(configuration: configuration)
self.customManager!.session.configuration.HTTPAdditionalHeaders = [
"Authorization": "Bearer \(accessToken!)" ]
}
func yourFunc() {
let URL = NSURL(string: identityURL)
var mutableURLRequest = NSMutableURLRequest(URL: URL!)
let request = self.customManager!.request(mutableURLRequest)
request.responseJSON {
(request, response, data, error) in
if let response = response {
// Your code
}
}
func HTTPHeader(param : NSDictionary)
{
var username: AnyObject? = param[kAPIUsername]
var password: AnyObject? = param[kAPIPassword]
var str = "\(username!):\(password!)"
let base64Encoded = BaseVC.sharedInstance.encodeStringToBase64(str)
Manager.sharedInstance.session.configuration.HTTPAdditionalHeaders = [
"Authorization": "Basic \(base64Encoded)",
]
}
func encodeStringToBase64(str : String) -> String
{
// UTF 8 str from original
// NSData! type returned (optional)
let utf8str = str.dataUsingEncoding(NSUTF8StringEncoding)
// Base64 encode UTF 8 string
// fromRaw(0) is equivalent to objc 'base64EncodedStringWithOptions:0'
// Notice the unwrapping given the NSData! optional
// NSString! returned (optional)
let base64Encoded = utf8str!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions(rawValue: 0))
return base64Encoded;
}
func GET()
{
HTTPHeader(param, token: token)
request(.GET, API URL , encoding: .JSON)
.progress { bytesWritten, totalBytesWritten, totalBytesExpectedToWrite in
//progress
}
.responseJSON {
(request, response, json, error) -> Void in
//get response here
}
}
might be help with link: how to use Alamofire with custom headers