How To Create an App Like Instagram With a Web Service Backend – Part 1/2

This is a blog post by iOS Tutorial Team member Marin Todorov, a software developer with 12+ years of experience, an independent iOS developer and the creator of Touch Code Magazine. There’s no doubt photography apps have huge momentum on the App Store. With the iPhone 4’s awesome camera and fast processor, taking photos and […] By Marin Todorov.

Leave a rating/review
Save for later
Share
You are currently viewing page 4 of 5 of this article. Click here to view the first page.

Getting a Little Salty

Select Storyboard.storyboard, and notice how the Photo Stream presents the modal Login dialogue. Next you’re going to authorize the user on this screen, by asking them to login or register with the application.

Photo!

Switch to PhotoScreen.m (it’s inside the Screens folder) and import the API class by adding the following code under the existing #import statement:

#import "API.h"

The above allows you to refer to the API class from within PhotoScreen.

Next, at the end of viewDidLoad, add this code to check whether the user is already authorized:

if (![[API sharedInstance] isAuthorized]) {
    [self performSegueWithIdentifier:@"ShowLogin" sender:nil];
}

Here you just call isAuthorized, which you added just moments ago to the API class. If the user is not authorized, you call the segue called ShowLogin to show the Login screen modally.

If you want to have some fun, run the project and tap on the top right button – this should show the login screen! Fun!

Login or register screen

Of course, if you did the above, then you noticed that neither the Login nor Register buttons work. So switch your focus to the Login screen and add some functionality to it!

First, add a quick usability enhancement. Add a viewDidLoad method like this one to LoginScreen.m just below the @implementation line:

-(void)viewDidLoad {
    [super viewDidLoad];
    
    //focus on the username field / show keyboard
    [fldUsername becomeFirstResponder];
}

Nice! The user doesn’t need to tap on the username field; the keyboard just pops up by itself. That was easy – let’s go on!

At the top of the source file, just below the two import directives add:

#import "API.h"
#include <CommonCrypto/CommonDigest.h>

#define kSalt @"adlfu3489tyh2jnkLIUGI&%EV(&0982cbgrykxjnk8855"

Whoa there! What’s that?!

First you import the API class. Then you include the built-in iOS cryptographic library. Okay, makes sense…

The string that looks like rubbish is a salt string that you’re going to use to make the user password a wee bit more difficult to hack. Instead of passing the plaintext password to the server for anyone who dumps the database to easily see, we’ll munge it a bit instead using a technique called hashing with salt.

This is not bulletproofing your server-client model at all, but it’s a good start. If you want to know more about salting the passwords you’re storing, have a look at salting passwords and rainbow tables.

Note: The focus of this tutorial is not on security, so hashing the password with salt is as far as we’re going to go here. Sometime soon, we hope to write another tutorial specifically focused on username/password security with respect to web services ;]

Look for a moment at the login screen. You always have the same text fields: username and password. The only difference between the login and register use cases is the actual call to the API: otherwise the data sent over is the same.

This means you only need one method to handle taps on both the login and register buttons. To determine whether to send a login or register command to the server, you’ll just check which button was tapped.

Both the login and register buttons send a btnLoginRegisterTapped: message to the view controller class. This is going to be a rather long method, so you’ll go through each step carefully. Inside the empty btnLoginRegisterTapped: in LoginScreen.m, add this code:

//form fields validation
if (fldUsername.text.length < 4 || fldPassword.text.length < 4) {
    [UIAlertView error:@"Enter username and password over 4 chars each."];
    return;
}

//salt the password
NSString* saltedPassword = [NSString stringWithFormat:@"%@%@", fldPassword.text, kSalt];

First you do a simple check on the entered username and password to determine whether they’re long enough (you could implement more checks if you wish). Then you add the salt to the password string. The next step is hashing the salted password. Add this code to the method:

//prepare the hashed storage
NSString* hashedPassword = nil;
unsigned char hashedPasswordData[CC_SHA1_DIGEST_LENGTH];

//hash the pass
NSData *data = [saltedPassword dataUsingEncoding: NSUTF8StringEncoding];
if (CC_SHA1([data bytes], [data length], hashedPasswordData)) {
    hashedPassword = [[NSString alloc] initWithBytes:hashedPasswordData length:sizeof(hashedPasswordData) encoding:NSASCIIStringEncoding];
} else {
    [UIAlertView error:@"Password can't be sent"];
    return;
}

You declare two variables: hashedPassword will hold the string of the hashed and salted password, while hashedPasswordData is a plain C array, which you will use as an intermediate storage for the hashed data.

Using dataUsingEncoding: you get the data bytes from the salted password. Here's where the magic happens: CC_SHA1() gets the bytes of the salted password, performs SHA1 hashing on them and stores the result in hashedPasswordData. Next, you quite easily create an NSString out of the data bytes. This is the hashed password you will send to the server.

Phew! The heavy work is done. Now you just need to make the call to the API.

First you should detect whether the user tapped the login or register button, and prepare the correct parameters for the API call. Since the register button has a tag of "1" (this was set via Interface Builder when the skeleton project was originally created), this is quite easy:

//check whether it's a login or register
NSString* command = (sender.tag==1)?@"register":@"login";
NSMutableDictionary* params =[NSMutableDictionary dictionaryWithObjectsAndKeys: 
 command, @"command",
 fldUsername.text, @"username",
 hashedPassword, @"password",
 nil];

Now that you have all the parameters for the call prepared, it's really easy to make the actual call:

    
//make the call to the web API
[[API sharedInstance] commandWithParams:params
                           onCompletion:^(NSDictionary *json) {
                           //handle the response
								
                           }];

The result from the server (or an error if there was a communication problem) will be passed as an NSDictionary to the block above. Let's dive into handling that response. Replace the "//handle the response" comment with:

//result returned
NSDictionary* res = [[json objectForKey:@"result"] objectAtIndex:0];

if ([json objectForKey:@"error"]==nil && [[res objectForKey:@"IdUser"] intValue]>0) {
   //success
   
} else {
   //error
   [UIAlertView error:[json objectForKey:@"error"]];
}

json is an NSDictionary and, as per the PHP API code you wrote earlier, it should hold a result key. You fetch another dictionary from within this key – hopefully that's the info of the logged user!

You then check whether an error has been returned, or if the user info is invalid, and if so, you display an error alert. Otherwise, you log in the user and take him/her to the Photo screen. To do that, replace the "//success" line with:

[[API sharedInstance] setUser: res];
[self.presentingViewController dismissViewControllerAnimated:YES completion:nil];

//show message to the user
[[[UIAlertView alloc] initWithTitle:@"Logged in" 
                           message:[NSString stringWithFormat:@"Welcome %@",[res objectForKey:@"username"] ]
                         delegate:nil 
                cancelButtonTitle:@"Close" 
                 otherButtonTitles: nil] show];

You store the user data to the API class and dismiss the Login dialogue. A nice alert also pops up to congratulate the user by their name. Sweet!

To recap: if the user wants to register with the system, this method will register and log them in at the same time. Alternatively, the user can use an existing user account and password to simply log in to the system. If the login was unsuccessful, you show the error message from the server. It's all so very easy :]

That's an awesome job so far! Everything should work right now, so fire up the project and go to the login screen. Choose a username and a password and tap on register. If you have a working server environment, you should see the Login screen disappear and the Photo screen should be now accessible! Awesome!

Logged in the app

Contributors

Over 300 content creators. Join our team.