I am currently developing my first iPhone application (although I have many years of experience as a web developer). Itβs hard for me to figure out how to handle my login better, and I'm looking for some tips on how to do this. The more I think about all the things that might be wrong when logging in, the more my brain wants to jump out of my head. I am very upset about this and really can use some tips from more experienced iPhone developers. Thanks in advance for your help.
My goal is to support Facebook Connect in the first version of the application, and then support other single sign-on services (Twitter, Google, etc.), as well as my own user account system in future versions. The current plan should have a MySQL table on the server that looks something like this:
users (id, nickname, facebook_id, ...)
When a user first logs into the application via Facebook, an entry will be created for them in this table. You might think that this is not necessary, but it will allow me to subsequently switch to other services. For example, I could do this:
users (id, nickname, facebook_id, twitter_id, google_id, username, ...)
This table will have fields with a null value for facebook_id, twitter_id, google_id and username. If the user logs in with facebook, they will have facebook_id. Twitter users will have twitter_id, Google users will have google_id, and my own users will have a username. All of them will be uniquely identified by my own identifier, no matter which login system they use.
Thus, it is very convenient for me to work with user accounts. I can configure a web service that the application can call to create / retrieve users, check logins, etc. No problems.
The problem I am facing is implementing the correct input stream with the iPhone interface components. My application uses the UITabBarController, which serves as the main navigation. One of the tabs is marked as "My Account" and contains information about the user who is logged in. If the user clicks on the "My Account" tab, they are displayed as a table view that serves as a submenu. It has options like My Profile, Settings, and some other things. If they click on any of these menu items and they are not logged in, then I use the presentViewController function to open the login screen. They click "login with facebook" and go through the typical Facebook login process. When they completed this process, I use rejectViewController to remove the login page and display the page they were trying to access. If they canceled the login or if the login failed, I use popViewControllerAnimated in the UINavigationController to send them back to the "My Account" submenu. For those of you who have a hard time considering this, check out the Amazon app. This is almost the same (just click on the "Advanced" tab when you are not logged in and are not trying to click one of the menu items below it).
Everything works very well, and I am pleased with that. But here, where I am confused:
What should I do if they are located at several levels in the UINavigationController on the My Account tab and their registration session ends?
Take, for example, a Facebook login. Facebook uses session tokens to log in. Tokens expire after a certain time. Let's say a user goes to "My Account", then clicks "My Profile" and then clicks "Edit" and displays a screen on which they can edit their profile information. Therefore, to view this page, they obviously need to authenticate. In fact, they take 2-3 levels deep in the pages that need to be authenticated. Now let me say that they are interrupted by a phone call or something else and forget about what they are doing. The next time they get access to the application, a week later, when their login period expires. I can handle this in several ways. None of them seem big to me.
Decision No. 1
The method of the AppDelegate class will be automatically called in the Facebook SDK, which notifies me of an expired session. Since I received a notification about the expiration of the session at the AppDelegate level, I have no idea which page the user is currently looking at and whether it needs to be authenticated in order to use it. To get around this, I can have all ViewControllers that require login in order to extend the "ProtectedViewController" class or something that indicates that the user must be logged in to see this page. Then, when the AppDelegate is notified of the expiration of the session, it will try to find out what the current ViewController is and check whether it extends the "ProtectedViewController". If so, enter the login screen. If the user successfully logs in, everything happens as usual. If not, then return the user to the first screen of the application, where they should start all over again. This is bad, because the user will lose everything that he has already typed, but I see no way to avoid this solution.
Decision number 2
Ignore the session expiration event at the AppDelegate level and instead, do the following: before performing any action that requires the user to log in (for example, when the user clicks the Save button on the Edit Profile page), check that they are still logged into the system. If not, enter the login screen. If the user cannot log in, send him back to the home screen. This solution is a pain in the ass, because I have to check almost everything that the user does in the protected area of ββthe application - when they view the page, when they click the button - almost everything.
I would also prefer not to send the user back to the start screen of the application if he cannot re-authenticate. Instead, in this case, I would prefer to send the user a backup of the UINavigationController in the My Account menu - this is the nearest page for which no login is required. Of course, I could do it tough, but I'm looking for a solution / template that works a little more naturally and that I can reuse it in other applications.
I would really appreciate some advice. Of course, I am not the first person in the world who needed to solve this problem. Unfortunately, Google did not help much.
Thanks.
EDIT: Another idea is to subclass the UIViewController (for example, "ProtectedViewController") and implement the "viewWillAppear" method. Inside this method, I can check if the user is logged in. If not, then I am shifting the login page. However, I still do not know how to handle the case when they cannot log in. This solution has a problem: if the user session expires when he uses the application, I will not re-check them until the next time they click on the new view. If they already look at the edit page and click the "Save" button, they will not be re-authenticated. But perhaps this is a step closer to the solution.