send token to server Swift 3 - ios

i'm trying to send a token to my server to check if token is still valid or has expired. the token value is pulled from saved data on the device. But no matter what i try it keeps giving me "missing token" which is the status message for when i've sent empty string.
// load content in user var
user = UserDefaults.standard.value(forKey: "parseJSON") as? NSDictionary
// if user is once logged in / register, keep him logged in
if user != nil {
print(user as Any)
let userToken = user!["token"] as? String
let url = NSURL(string: "http://fmm.dummy.com/api/v1/auth/me")!
var request = URLRequest(url: url as URL)
request.setValue("Bearer \(String(describing: userToken))", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
When i edited and did this, the error message change to "invalid token" which meant i was sending something. it just wasn't correct
// load content in user var
user = UserDefaults.standard.value(forKey: "parseJSON") as? NSDictionary
// if user is once logged in / register, keep him logged in
if user != nil {
print(user as Any)
let userToken = user!["token"] as? String
let a: Character = "<"
let b: Character = ">"
let url = NSURL(string: "http://fmm.dummy.com/api/v1/auth/me")!
var request = URLRequest(url: url as URL)
request.setValue("Bearer .append\(a)\(String(describing: userToken)).append\(b)", forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
//launch session
URLSession.shared.dataTask(with: request) { data, response, error in
can someone please help me figure out what am doing wrong?
thanks
///EDIT
Hi when i edited as you had suggested and came up with this, i couldn't even print to console. Here is the full code for your consideration. Thanks for the response.
if let user = UserDefaults.standard.object(forKey: "parseJSON") as? [String:Any],
let userToken = user["token"] as? String {
let url = URL(string: "http://fmm.dummy.com/api/v1/auth/me")!
var request = URLRequest(url: url)
let tokenString = "Bearer " + userToken
request.setValue(tokenString, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
//launch session
URLSession.shared.dataTask(with: request) { data, response, error in
//check if no error
if error == nil{
do {
let json = try JSONSerialization.jsonObject(with: data!, options: .mutableContainers) as? NSDictionary
guard let parseJSON = json else{
print ("Error While Parsing")
return
}
print(parseJSON)
let statusMsg = parseJSON["status"] as? String
if statusMsg == "OK"{
//token still valid
self.login()
}else {
//token is invalid
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = parseJSON["status_msg"] as! String
appDelegate.infoView(message: message, color: colorSmoothRed)
})
}
}catch{
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = "\(error)"
appDelegate.infoView(message: message, color: colorSmoothRed)
})
return
}
}else{
// get main queue to communicate back to user
DispatchQueue.main.async(execute: {
let message = error!.localizedDescription
appDelegate.infoView(message: message, color: colorSmoothRed)
})
return
}
}.resume()
}
I'm trying to write code in appdelegate.swift that checks if the token saved from a previous login is still valid or has expired! the saved object on the user device is as follows. When i print user to the console i get this. ::--
Optional({
response = {
token = "eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJzdWIiOjIsImlzcyI6Imh0dHA6XC9cL3htbS54bW9iaWxlbW9uZXkuY29tXC9hcGlcL3YxXC9hdXRoIiwiaWF0IjoxNDk2ODUyNTkxLCJleHAiOjE0OTY4NTYxOTEsIm5iZiI6MTQ5Njg1MjU5MSwianRpIjoiOTFhYjE0MjZkMGZmN2RjZDVjOTQzNTlkZGY4OGY0ZmYifQ.WaQFprfRbJMDQ72IORtWrcSmUqY3EaJp5BAqjijvUAc";
verified = 1;
};
status = OK;
})

You are using too many optionals which can cause unexpected literal "Optional(<value>)" when calling the description method.
Unwrap all optionals safely with optional bindings:
if let user = UserDefaults.standard.object(forKey: "parseJSON") as? [String:Any],
let userToken = user["token"] as? String {
let url = URL(string: "http://fmm.dummy.com/api/v1/auth/me")!
var request = URLRequest(url: url)
let tokenString = "Bearer " + userToken
request.setValue(tokenString, forHTTPHeaderField: "Authorization")
request.httpMethod = "POST"
...
As always, never use valueForKey to get a single object from UserDefaults, use always objectForKey, and never use NSDictionary for a property list compliant dictionary, use always [String:Any].

Related

iOS - Swift : fetching data from database in main thread, not in background

In my iOS App i'm able to download data from a database, but actually all the operations are made in background and the main thread is still active, even the GUI. I also tried to make a 'sleep' with
DispatchQueue.main.asyncAfter(deadline: .now() + .seconds(3)) { ... }
With this delay everthing works fine, but it's not a good solution. How can i change my code to do this in the main thread? Possibly with loadingIndicator.
This is my code (checking if username exists):
func CheckIfUsernameExists(username : String, passwordFromDb : inout String, errorMsg : inout String)
{
//declare parameter as a dictionary which contains string as key and value combination. considering inputs are valid
var _errorMsg = ""
var _psw = ""
var parameters : [String : Any]?
parameters = ["username": username,
"action": "login"]
print(parameters!)
let session = URLSession.shared
let url = "http://www.thetestiosapp.com/LoginFunctions.php"
let request = NSMutableURLRequest()
request.url = URL(string: url)!
request.httpMethod = "POST"
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("application/json", forHTTPHeaderField:"Accept")
request.setValue("application/x-www-form-urlencoded", forHTTPHeaderField:"Content-Type")
do{
request.httpBody = try JSONSerialization.data(withJSONObject: parameters!, options: .sortedKeys)
let task = session.dataTask(with: request as URLRequest, completionHandler: {(data, response, error) in
if let response = response {
let nsHTTPResponse = response as! HTTPURLResponse
let statusCode = nsHTTPResponse.statusCode
print ("status code = \(statusCode)")
}
if let error = error {
print ("\(error)")
}
if let data = data {
do{
_psw = self.parseJSON_CheckIfUsernameExists(data, errorMsg: &_errorMsg)
}
}
})
task.resume()
}catch _ {
print ("Oops something happened buddy")
errorMsg = "Usarname non recuperato (1)"
}
passwordFromDb = _psw
errorMsg = _errorMsg
}
You’re attempting to update passwordFromDb and errorMsg at the end of this method. But this is an asynchronous method and and those local variables _psw and _errorMsg are set inside the closure. Rather than trying to defer the checking of those variables some arbitrary three seconds in the future, move whatever “post request” processing you need inside that closure. E.g.
func CheckIfUsernameExists(username : String, passwordFromDb : inout String, errorMsg : inout String) {
//declare parameter as a dictionary which contains string as key and value combination. considering inputs are valid
let parameters = ...
let session = URLSession.shared
var request = URLRequest()
...
do {
request.httpBody = ...
let task = session.dataTask(with: request) { data, response, error in
if let httpResponse = response as? HTTPURLResponse,
let statusCode = httpResponse.statusCode {
print ("status code = \(statusCode)")
}
guard let data = data else {
print (error ?? "Unknown error")
return
}
let password = self.parseJSON_CheckIfUsernameExists(data, errorMsg: &_errorMsg)
DispatchQueue.main.async {
// USE YOUR PASSWORD AND ERROR MESSAGE HERE, E.G.:
self.passwordFromDb = password
self.errorMsg = _errorMsg
// INITIATE WHATEVER UI UPDATE YOU WANT HERE
}
}
task.resume()
} catch _ {
print ("Oops something happened buddy")
errorMsg = "Usarname non recuperato (1)"
}
}

Json response "GET" request: "No session Found" - Swift

I want to make a "GET" request to apache web server to retrieve some data. Before making the above request, I log in making a "POST" request, the web server opens a new session and I get the json response:
gotten json response dictionary is
["user": {
email = "asd#asd.it";
password = "<null>";\\ for security reason it doesn't return the password
sessionID = 6C61269BB7BB40682E96AD80FF8F1CB7;
}]
So far it's all correct. But then when I try to make the "GET" request to retrive the user's data, I get this response:
gotten json response dictionary is
["message": {
errorCode = F01;
errorDetails = "No session is found in the server, either you have not set the JSESSIONID cookie or the session does not exists";
message = "No session Found";
}]
The code for the "POST" request is:
let urlComp = NSURLComponents(string: "http://localhost:8080/mnemosyne/auth")!
let postDict: [String:Any] = ["email": "asd#asd.it", "password" : "password"]
var items = [URLQueryItem]()
for (key,value) in postDict {
items.append(URLQueryItem(name: key, value: value as? String))
}
urlComp.queryItems = items
var urlRequestAuth = URLRequest(url: urlComp.url!, cachePolicy: .reloadIgnoringLocalAndRemoteCacheData, timeoutInterval: 10.0 * 1000)
urlRequestAuth.httpMethod = "POST"
let postData = try? JSONSerialization.data(withJSONObject: postDict, options: [])
urlRequestAuth.httpBody = postData
let taskAuth = URLSession.shared.dataTask(with: urlRequestAuth) { (data, response, error) in
guard error == nil else {
print(error as Any)
return
}
guard let content = data else {
print("No data")
return
}
guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String: Any] else {
print("Not containing JSON")
return
}
print("gotten json response dictionary is \n \(json)")
}
taskAuth.resume()
This is the code for "GET":
let url = URL(string: "http://localhost:8080/mnemosyne/rest/task")
var request = URLRequest(url: url!)
let taskTask = URLSession.shared.dataTask(with: request) { (data, response, error) in
guard error == nil else {
print ("error: \(error!)")
return
}
guard let content = data else {
print("No data")
return
}
guard let json = (try? JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers)) as? [String: Any] else {
print("Not containing JSON")
return
}
print("gotten json response dictionary is \n \(json)")
}
taskTask.resume()
What's the problem? How can I pass in the request the session Id that I want to use?
I think you need send sessionID in your GET request.
I would at first try some util like Postman or RESTed free apps, to test request and understand how to send correct POST request.
Depending on server implementation - you could send session ID as a part of url, in POST body or in POST header.

FCM unable receive push notification after app ugrade

I am using FCM for my app. In first build I have successfully added firebase. Then I have upgraded app to new version and it doesn't receive any push notification.
Even firebase server call retruns proper device data, i.e. whether the device is registered or not. Here is the code:
func getUserTopicSubscribeWithToken() {
print("getUserTopicSubscribeWithToken")
var token = ""
if Messaging.messaging().fcmToken != nil {
token = Messaging.messaging().fcmToken!
}
let urlString = "https://iid.googleapis.com/iid/info/\(token)?details=true"
let url = URL(string: urlString.addingPercentEncoding(withAllowedCharacters: CharacterSet.urlQueryAllowed)!)
var request = URLRequest(url: url!)
request.setValue("application/json", forHTTPHeaderField: "Content-Type")
request.setValue("key=\(serverKey)", forHTTPHeaderField: "Authorization")
let session = URLSession.shared
session.dataTask(with: request) {data, response, err in
print("Entered the completionHandler")
if (data != nil && err == nil) {
if let topics = String.init(data: data!, encoding: .utf8) {
print("topics :: \(topics)")
let cleanResult = topics.replacingOccurrences(of: "\\", with: "")
if let dict = JSONResultHelper.convertToDictionary(text: cleanResult) {
print("dict :: \(dict)")
if let allTopics = dict["rel"] as? [String:Any] {
print("allTopics :: \(allTopics)")
if let values = allTopics["topics"] as? [String:Any] {
print("values :: \(values)")
for key in values.keys {
AppDelegate.sharedInstance.moduleManager().apiModule?.subscribeToChannel(channelName: key)
}
}
}
}
}
}
}.resume()
}
This call gives me fcm details as expected.
I have also tried to send notification to single device using fcm token, but It didn't work.
Please Note:
It is working perfectly fine on fresh install but not on upgraded one.

authenticating json data, it does not take username and password in swift? can you correct me my code?

http://beta.json-generator.com/api/json/get/E1jKVbplX I have registered successfully. i am struck in authentication. i accessed all data. but i struck in accessing individual user data. please see below code and correct me. var email = “bhupal”
var pwd = “k”
//
let parameters: Dictionary<String, AnyObject> = ["Email": email as AnyObject, "Password": pwd as AnyObject,"Type" : "Organization" as AnyObject,"Mode" : "Register" as AnyObject]
//create the url with URL
let url = URL(string: "http://beta.json-generator.com/api/json/get/E1jKVbplX ")! //change the url
let session = URLSession.shared
//now create the URLRequest object using the url object
var request = URLRequest(url: url)
request.httpMethod = "GET" //set http method as GET
do {
request.httpBody = try JSONSerialization.data(withJSONObject: parameters, options: .prettyPrinted) // pass dictionary to nsdata object and set it as request body
} catch let error {
print(error.localizedDescription)
}
request.addValue("application/json", forHTTPHeaderField: "Content-Type")
request.addValue("application/json", forHTTPHeaderField: "Accept")
//
let task = URLSession.shared.dataTask(with: url) { (data, response, error) in
if error != nil
{
print ("ERROR")
}
else
{
if let content = data
{
do
{
//Array
let myJson = try JSONSerialization.jsonObject(with: content, options: JSONSerialization.ReadingOptions.mutableContainers) as AnyObject
print(myJson)
print("--------")
print(myJson[0])
print(myJson[1])
print("--------")
email = myJson["Email"] as? String
pwd = myJson["Password"] as? String
print("--------")
print(email)
print(pwd)
print("--------")
}
catch
{
}
}
}
}
task.resume()
Your response is Array of Dictionary so myJson[0] will return you a dictionary object and in that dictionary you should try accessing value for Email or Password.
You can try below code to access email and password :
for dict in myJson { // myJson is array and dict will of dictionary object
let email = dict[Email]
let password = dict[Password]
print("--------")
print("Email is : \(email)")
print("Password is : \(password)")
print("--------")
}
Note : You make need to improvise it.

NSURLSession.sharedSession().dataTaskWithRequest(request) being executed last

I'm having a problem with NSURLSession.sharedSession().dataTaskWithRequest(request). I want to authenticate my app against some API and if the authentication is successful then the app will let the user to authorise health kit and finally fetch some data from there.
I have this in my viewDidLoad()
print ("AUTHORIZING APIGEE!!!")
authorizeApigee()
if (self.errorApigee == 0) {
print ("APIGEE AUTHORIZED!")
// We cannot access the user's HealthKit data without specific permission.
print ("AUTHORIZING HEALTHKIT!!")
getHealthKitPermission()
print ("HEALTHKIT AUTORIZED!")
} else {
print ("APIGEE UNAUTHORIZED!")
}
and this is the authorising function:
// Authenticating app with Apigee Health APIx
func authorizeApigee(){
// Send HTTP GET Request
let scriptUrl = "https://fhirsandbox-prod.apigee.net/oauth/v2"
let urlWithParams = scriptUrl + "/accesstoken?grant_type=client_credentials"
let myUrl = NSURL(string: urlWithParams);
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST"
// Add Basic Authorization
let username = "****"
let password = "****"
let loginString = NSString(format: "%#:%#", username, password)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
request.setValue(base64LoginString, forHTTPHeaderField: "Authorization")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
// Check for error
if error != nil
{
self.errorApigee = 1
print("error=\(error)")
return
}
// Print out response string
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
}
task.resume()
}
The problem is that even though authorizeApigee() is called, the app stops at NSURLSession.sharedSession().dataTaskWithRequest(request), goes out of the function, obviously errorApigee variable is not updated and therefore it goes to the next step of authorising health kit without authorising Apigee. Finally when health kit was authorised it goes back and authorises Apigee.
Any idea why this might happen at all?
Any tip would be greatly appreciated!
This is simple example how to use completion :
func authorizeApigee(completion: (auth: Bool) -> Void) {
// Send HTTP GET Request
let scriptUrl = "https://fhirsandbox-prod.apigee.net/oauth/v2"
let urlWithParams = scriptUrl + "/accesstoken?grant_type=client_credentials"
let myUrl = NSURL(string: urlWithParams);
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST"
// Add Basic Authorization
let username = "****"
let password = "****"
let loginString = NSString(format: "%#:%#", username, password)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
request.setValue(base64LoginString, forHTTPHeaderField: "Authorization")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
// Check for error
if error != nil
{
self.errorApigee = 1
print("error=\(error)")
completion(auth: false)
}
// Print out response string
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
completion(auth: true)
}
task.resume()
}
And how to use :
self.authorizeApigee { (auth) -> Void in
if (auth) {
getHealthKitPermission()
} else {
//print errors
}
}
NSURLSession.sharedSession().dataTaskWithRequest() is executed in another thread. It's so that the main application thread doesn't hang and wait for the request to complete. If you want a code block to run after the async task is complete, I suggest you use a completion block.
You need to use closure because api calling work in async manner so first change your function definition like this
func authorizeApigee(completion: (Int) -> ()){
let scriptUrl = "https://fhirsandbox-prod.apigee.net/oauth/v2"
let urlWithParams = scriptUrl + "/accesstoken?grant_type=client_credentials"
let myUrl = NSURL(string: urlWithParams);
let request = NSMutableURLRequest(URL:myUrl!);
request.HTTPMethod = "POST"
// Add Basic Authorization
let username = "****"
let password = "****"
let loginString = NSString(format: "%#:%#", username, password)
let loginData: NSData = loginString.dataUsingEncoding(NSUTF8StringEncoding)!
let base64LoginString = loginData.base64EncodedStringWithOptions(NSDataBase64EncodingOptions())
request.setValue(base64LoginString, forHTTPHeaderField: "Authorization")
let task = NSURLSession.sharedSession().dataTaskWithRequest(request) {
data, response, error in
// Check for error
if error != nil
{
completion(0)
print("error=\(error)")
return
}
// Print out response string
let responseString = NSString(data: data!, encoding: NSUTF8StringEncoding)
print("responseString = \(responseString)")
completion(1)
}
task.resume()
}
Now call your function like this
self.authorizeApigee() { (result) -> () in
if result == 0 {
print ("APIGEE AUTHORIZED!")
// We cannot access the user's HealthKit data without specific permission.
print ("AUTHORIZING HEALTHKIT!!")
getHealthKitPermission()
print ("HEALTHKIT AUTORIZED!")
} else {
print ("APIGEE UNAUTHORIZED!")
}
}

Resources