Reputation: 1680
I am developing an App that will interface with a web server (PHP with MySQL back end) using web views. I have the application working with static URL's as tests, but now I need to adjust for actual user interaction.
I have been looking for solutions to HTTP authentication but believe the phrase to be incorrect as most of the search results I get are all related to "REST" requests. I will be using a URL (PHP / MySQL) to validate authentication and do not believe that qualifies as REST based on my experience.
I do not have SSL as of yet on this server so I am not sure what options are available via Cocoa.
Questions I have:
Is there a way to create a View that loads if the account ID isn't already stored locally?
If so, can i code the app to supersede the storyboard I have created if authentication is needed?
If step 1 and 2 work, how can I interface with my web server to authenticate? ( preferred method is to submit user email and the MD5 of the password as that is what is currently stored in the database)
Ideally i would love to just submit a url like "[email protected]&password=(md5hash)" and have the provided response either give me "auth=true&accountID=5" or "auth=false" ... then use the iPhone app to either report an auth error to the user or save the account id to NSUserDefaults for future use (to bypass auth later) and load the normal storyboard already in place.
Any recommendations would be appreciated.
Thanks,
Silver Tiger
Upvotes: 2
Views: 3452
Reputation: 1680
I didn't have enough space to comment in the notes. Here's the final code. THough not what i wanted it gets the job done:
In order to get JSONValue to work i had to download and include in my project the json frameowrk as seen here:
https://github.com/stig/json-framework
Once I had that in place I was getting an incomplete error from the JSONValue function. my original URL request to my PHP page request was providing the JSON response as follows:
{ "success": "0", "AccountID: "4", "error": "" }
For some reason the JSONValue function did not like this output and I had to change it to a more basic less preferred version as follows:
["0","4",""]
Once I had this working the final copy of the code is as follows:
In my main view that loads on app launch I added the following to determine if there was an existing account ID and launch the "Login" view if it was not present:
- (void)viewDidLoad
{
NSString *accountID = [[NSUserDefaults standardUserDefaults] stringForKey:@"AccountID"];
if (![accountID length]) {
UIViewController *login = [self.storyboard instantiateViewControllerWithIdentifier:@"Login"];
[self presentModalViewController:login animated:YES];
}
[super viewDidLoad];
}
The login is nothing more than 2 text fields and a button for authentication. This is the function I added to the button, and it works currently:
-(IBAction)authenticate:(id)sender{
// This will be the validation code
// First we'll grab the field values
NSString *currentEmail = emailField.text;
NSString *currentPassword = passField.text;
// Now we will grab the user default settings (saved preferences)
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
// build the request to update status
NSString *myURL = [NSString stringWithFormat:@"http://www.myurl.com/auth.php?e=%@&p=%@",currentEmail,currentPassword];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] init]; [request setURL:[NSURL URLWithString:myURL]];
[request setHTTPMethod:@"GET"];
NSData *returnData = [NSURLConnection sendSynchronousRequest:request returningResponse:nil error:nil];
NSString *responseString = [[NSString alloc] initWithData:returnData encoding: NSUTF8StringEncoding];
NSArray *responseArray = [responseString JSONValue];
NSString *success = [responseArray objectAtIndex:0];
NSString *AccountID = [responseArray objectAtIndex:1];
NSString *error = [responseArray objectAtIndex:2];
if([success boolValue]) {
NSLog(@"User is Authenticated");
UIAlertView *auth1 = [[UIAlertView alloc] initWithTitle:@"T-of-U" message:@"Successfully Authenticated" delegate:self cancelButtonTitle:@"ok" otherButtonTitles: nil];
[auth1 show];
[defaults setObject:AccountID forKey:@"AccountID"];
[self dismissModalViewControllerAnimated:YES];
} else {
NSString *authMessage = error;
UIAlertView *auth2 = [[UIAlertView alloc] initWithTitle:@"Authentication Failed:" message:authMessage delegate:self cancelButtonTitle:@"ok" otherButtonTitles: nil];
[auth2 show];
}
}
I would have preferred a key value pair NSDictionary, but every time I sent the json response with key value pairs, the JSONValue failed so I ended up just making it a simple json response and reference objects in array locations to get my variables.
if there is a way to get key value pairs into a dictionary that would be great, though I may not be forming my json response properly (PHP has the json_encode($data) method that creates the json as expected, but the Objective C function won't parse it).
Upvotes: 2
Reputation: 14164
You are pretty close with your thinking. I use a very similar approach to my user login process.
I currently salt and hash the email and password into 1 40 char token. If the login returns successful, I save the token to NSUserDefaults. I use this token for all other web requests going forward until the user logs out, at which time I delete the user defaults.
Here are a few snippets I use for the same process:
// see if a login already exists
NSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];
self.token = [defaults stringForKey:@"token"];
// if the token is nil/blank, launch login view
if(self.token == nil || [self.token isEqualToString:@""]) {
[self loadStartView];
return;
}
// build the request to update status
[[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyNever];
NSString *stringData = [NSString stringWithFormat:@"<your api string here"];
NSString *requestData = stringData;
NSData *myRequestData = [NSData dataWithBytes: [requestData UTF8String] length: [requestData length]];
NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL: [NSURL URLWithString:[NSString stringWithFormat:@"<your url request here>"]]];
[request setHTTPMethod: @"POST"];
[request setHTTPBody: myRequestData];
NSData *jsonData = [NSURLConnection sendSynchronousRequest: request returningResponse: nil error: nil];
NSString *json = [[[NSString alloc] initWithData:jsonData encoding:NSUTF8StringEncoding] autorelease];
NSDictionary *payloadData = [json JSONValue];
[request release];
if([[payloadData objectForKey:@"success"] boolValue]) { // this is designed around my api, but you get the idea
//NSLog(@"updateStatus: %@", payloadData);
// updates the api version for every call
[defaults setObject:self.token forKey:@"token"];
}
Upvotes: 3