{"id":18271848,"url":"https://github.com/dennisreimann/AuthenticationController","last_synced_at":"2025-04-05T02:30:45.844Z","repository":{"id":656658,"uuid":"299390","full_name":"dennisreimann/AuthenticationController","owner":"dennisreimann","description":"The code for my recipe in the upcoming iPhone Recipes book","archived":true,"fork":false,"pushed_at":"2009-09-06T20:28:45.000Z","size":90,"stargazers_count":16,"open_issues_count":0,"forks_count":0,"subscribers_count":3,"default_branch":"master","last_synced_at":"2024-11-05T11:54:19.370Z","etag":null,"topics":[],"latest_commit_sha":null,"homepage":"http://dennisbloete.de","language":"Objective-C","has_issues":true,"has_wiki":null,"has_pages":null,"mirror_url":null,"source_name":null,"license":null,"status":null,"scm":"git","pull_requests_enabled":true,"icon_url":"https://github.com/dennisreimann.png","metadata":{"files":{"readme":"README","changelog":null,"contributing":null,"funding":null,"license":null,"code_of_conduct":null,"threat_model":null,"audit":null,"citation":null,"codeowners":null,"security":null,"support":null}},"created_at":"2009-09-06T19:59:19.000Z","updated_at":"2023-01-28T19:47:47.000Z","dependencies_parsed_at":"2022-08-16T10:35:18.281Z","dependency_job_id":null,"html_url":"https://github.com/dennisreimann/AuthenticationController","commit_stats":null,"previous_names":[],"tags_count":0,"template":false,"template_full_name":null,"repository_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennisreimann%2FAuthenticationController","tags_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennisreimann%2FAuthenticationController/tags","releases_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennisreimann%2FAuthenticationController/releases","manifests_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories/dennisreimann%2FAuthenticationController/manifests","owner_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners/dennisreimann","download_url":"https://codeload.github.com/dennisreimann/AuthenticationController/tar.gz/refs/heads/master","host":{"name":"GitHub","url":"https://github.com","kind":"github","repositories_count":247279282,"owners_count":20912857,"icon_url":"https://github.com/github.png","version":null,"created_at":"2022-05-30T11:31:42.601Z","updated_at":"2022-07-04T15:15:14.044Z","host_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub","repositories_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repositories","repository_names_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/repository_names","owners_url":"https://repos.ecosyste.ms/api/v1/hosts/GitHub/owners"}},"keywords":[],"created_at":"2024-11-05T11:39:32.962Z","updated_at":"2025-04-05T02:30:44.773Z","avatar_url":"https://github.com/dennisreimann.png","language":"Objective-C","funding_links":[],"categories":["etc"],"sub_categories":[],"readme":"Dennis Blöte\nhttp://dennisbloete.de\nmail@dennisbloete.de\n\nDraft for the iPhone Recipes Book, version 0.1 (08/28/2009)\n\n\nAuthentication handling\n=======================\n\nProblem\n-------\nMost applications that deal with users registered on a backend (like webapps) are likely to verify\nthe user credentials. This recipe explains how to extract the authentication functionality that\nhandles the workflow of prompting the user for credentials and verifying them at the backend. \n\n\n\nSolution\n--------\nA separate (Modal View) Controller that acts as the apps AuthenticationController and gets called by\nother controllers. This controller encapsulates the authentication logic so that it is cleanly separated\nfrom the rest of the app. The provided code is compatible for all iPhone OS from 2.0 on.\n\nThe basic procedure will work like this: The app looks for previously stored credentials and uses them to\nauthenticate the user. If there are no stored credentials, the user gets prompted for his username and\npassword. After that the backend gets called and we try to authenticate: In case of success the credentials\nget saved, otherwise the user gets alerted and is prompted for the username and password again.\n\nTo start, create a new UIViewController subclass called AuthenticationController and let Xcode generate an\naccompanying XIB file. The XIB will contain the login form with UITextFields for the username and password,\nas well as a submit and cancel button.\n\nThe interface for the AuthenticationController will look like this:\n\n//----- AuthenticationController.h -----\n\n#define kUsernameDefaultsKey @\"username\"\n#define kPasswordDefaultsKey @\"password\"\n\n@interface AuthenticationController : UIViewController {\n  @private\n\t  id target;\n\t  SEL selector;\n\t  UIViewController *viewController;\n\t  UIActionSheet *authSheet;\n\t  NSString *username;\n\t  NSString *password;\n\t  IBOutlet UITextField *usernameField;\n\t  IBOutlet UITextField *passwordField;\n\t  IBOutlet UIButton *submitButton;\n\t  IBOutlet UIButton *cancelButton;\n}\n \n@property (nonatomic, retain) NSString *username;\n@property (nonatomic, retain) NSString *password;\n \n- (id)initWithTarget:(id)theTarget andSelector:(SEL)theSelector andViewController:(UIViewController *)viewController;\n- (void)authenticate;\n- (IBAction)submit:(id)sender;\n- (IBAction)cancel:(id)sender;\n \n@end\n\n//----- AuthenticationController.h -----\n\nThe header file contains two macros which define the keys for saving and restoring the username and password.\nIt defines the outlets for the text fields and buttons that need to be connected in Interface Builder. You also\nneed to wire up the buttons with the appropriate actions called submit and cancel.\n\nThe AuthenticationController gets initalized with a target, selector and view controller. The target is the view\ncontroller or app delegate that holds a reference to the AuthenticationController and receives the selector after\nthe authentication process is finished. The passed view controller is the one that brings up the login view as a\nmoal view controller.\n\nBefore we will have a look at the implementation, lets examine how this will be used by the target - in this case\nan instance of an UIApplicationDelegate:\n\n//----- AuthAppDelegate.m -----\n\n- (void)authenticate {\n\tauthController = [[AuthenticationController alloc] initWithTarget:self \n\t                                                      andSelector:@selector(authenticationSucceeded:)\n\t                                                andViewController:navigationController];\n\t[authController authenticate];\n}\n\n- (void)authenticationSucceeded:(BOOL)success {\n\tNSLog(@\"Authentication succeeded: %@!\", success ? @\"YES\" : @\"NO\");\n\t[authController release];\n}\n\n//----- AuthAppDelegate.m -----\n\nThe AuthAppDelegate should hold a reference to an instance of the AuthenticationController and implement two\nmethods that deal with the authentication: The authenticate method initializes an AuthenticationController with\nthe AuthAppDelegate as target and the authenticationSucceeded method as selector. This selector will receive a\nboolean argument which tells us whether the authentication succeeded. The view controller is the root view controller\nof the app.\n\nAfter initializing the AuthenticationController we ask the instance to start an authentication process. If the \nrequest cannot be verified directly, the login screen will appear. In any case the authentication will result in\na call to the authenticationSucceeded: method which was passed as the selector to the AuthenticationController.\n\nLet's have a look at the authentication workflow: First of all there are some private methods that will be used\ninternally.\n\n//----- AuthenticationController.m -----\n\n@interface AuthenticationController ()\n- (void)failWithMessage:(NSString *)theMessage;\n- (void)startAuthentication;\n- (void)finishAuthenticationWithSuccess:(BOOL)success;\n- (void)presentLogin;\n- (void)dismissLogin;\n- (void)showAuthenticationSheet;\n- (void)dismissAuthenticationSheet;\n@end\n\n\n@implementation AuthenticationController\n\n@synthesize username, password;\n\n- (id)initWithTarget:(id)theTarget andSelector:(SEL)theSelector andViewController:(UIViewController *)theViewController {\n\t[super initWithNibName:@\"Authentication\" bundle:nil];\n\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\tself.username = [defaults stringForKey:kUsernameDefaultsKey];\n\tself.password = [defaults stringForKey:kPasswordDefaultsKey];\n\ttarget = theTarget;\n\tselector = theSelector;\n\tviewController = theViewController;\n\treturn self;\n}\n\n//----- AuthenticationController.m -----\n\nThe initializer loads the XIB file that was created along with the controller and tries to fetch the username and\npassword from the NSUserDefaults. The references are set without retaining the instances.\n\n//----- AuthenticationController.m -----\n\n- (void)viewDidLoad {\n  [super viewDidLoad];\n\tusernameField.text = username;\n\tpasswordField.text = password;\n}\n\n- (void)dealloc {\n\t[usernameField release];\n\t[passwordField release];\n\t[submitButton release];\n\t[cancelButton release];\n\t[username release];\n\t[password release];\n  [super dealloc];\n}\n\n- (IBAction)submit:(id)sender {\n\tself.username = usernameField.text;\n\tself.password = passwordField.text;\n\t[self authenticate];\n}\n\n- (IBAction)cancel:(id)sender {\n\t[self finishAuthenticationWithSuccess:NO];\n}\n\n- (void)authenticate {\n\tif (username.length \u003e 0 \u0026\u0026 password.length \u003e 0) {\n\t\t[self startAuthentication];\n\t} else {\n\t\t[self failWithMessage:@\"Please enter your username and password\"];\n\t}\n}\n\n- (void)startAuthentication {\n\t[self showAuthenticationSheet];\n\tNSURL *url = [NSURL URLWithString:@\"http://twitter.com/account/verify_credentials.xml\"];\n\tNSURLRequest *request = [NSURLRequest requestWithURL:url];\n\t[NSURLConnection connectionWithRequest:request delegate:self];\n}\n\n//----- AuthenticationController.m -----\n\nThe authenticate method verifies that the username and password fields are not left blank and starts the authentication\nrequest. To keep it simple we will use a NSURLConnection that will perform a HTTP Basic Auth. The following methods are\nhelper methods and their names describe most of their functionality:\n\n//----- AuthenticationController.m -----\n\n- (void)failWithMessage:(NSString *)theMessage {\n\t[self dismissAuthenticationSheet];\n\t[self presentLogin];\n\t[usernameField becomeFirstResponder];\n\tUIAlertView *alert = [[UIAlertView alloc] initWithTitle:@\"\" message:theMessage delegate:nil cancelButtonTitle:@\"OK\" otherButtonTitles:nil];\n\t[alert show];\n\t[alert release];\n}\n\n- (void)showAuthenticationSheet {\n\tauthSheet = [[UIActionSheet alloc] initWithTitle:@\"Authenticating, please wait...\" delegate:self cancelButtonTitle:nil destructiveButtonTitle:nil otherButtonTitles:nil];\n\tUIView *currentView = viewController.modalViewController ? viewController.modalViewController.view : viewController.view;\n\t[authSheet showInView:currentView];\n\t[authSheet release];\n}\n\n- (void)dismissAuthenticationSheet {\n\t[authSheet dismissWithClickedButtonIndex:0 animated:YES];\n\tauthSheet = nil;\n}\n\n- (void)presentLogin {\n\tif (viewController.modalViewController == self) return;\n\t[viewController presentModalViewController:self animated:YES];\n}\n\n- (void)dismissLogin {\n\tif (viewController.modalViewController != self) return;\n\t[viewController dismissModalViewControllerAnimated:YES];\n}\n\n- (void)finishAuthenticationWithSuccess:(BOOL)success {\n\tif (success) { // save credentials\n\t\tNSUserDefaults *defaults = [NSUserDefaults standardUserDefaults];\n\t\t[defaults setValue:username forKey:kUsernameDefaultsKey];\n\t\t[defaults setValue:password forKey:kPasswordDefaultsKey];\n\t\t[defaults synchronize];\n\t}\n\t[self dismissAuthenticationSheet];\n\t[self dismissLogin];\n\t[target performSelector:selector withObject:success];\n}\n\n//----- AuthenticationController.m -----\n\nIn case of success the finishAuthenticationWithSuccess: method saves the users credentials. After that the selector gets\ncalled with the boolean value telling the target whether the authentication was successful or not. The following part are\nNSURLConnection delegation methods that perform the verification. Depending on the scenario in your application this\npart is likely to be replaced by what you are actually using to verifythe users credentials.\n\n//----- AuthenticationController.m -----\n\n- (void)connection:(NSURLConnection *)connection didReceiveAuthenticationChallenge:(NSURLAuthenticationChallenge *)challenge {\n\tif ([challenge previousFailureCount] == 0) {\n\t\tNSURLCredential *credential = [[NSURLCredential alloc] initWithUser:username password:password persistence:NSURLCredentialPersistenceForSession];\n\t\t[challenge.sender useCredential:credential forAuthenticationChallenge:challenge];\n\t\t[credential release];\n\t} else {\n\t\t[challenge.sender cancelAuthenticationChallenge:challenge];\n\t}\n}\n- (void)connection:(NSURLConnection *)connection didReceiveData:(NSData *)data {\n\t[self finishAuthenticationWithSuccess:YES];\n}\n\n- (void)connection:(NSURLConnection *)connection didFailWithError:(NSError *)error {\n\t[self failWithMessage:@\"Please ensure that you are connected to the internet and that your username and password are correct\"];\n}\n\n@end\n\n//----- AuthenticationController.m -----\n\n\nDiscussion\n----------\n\nThis example stores the credentials in the NSUserDefaults and the password gets saved in clear text. You should think\nabout extending the code to use the keychain, so that the password is stored securely.\n","project_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdennisreimann%2FAuthenticationController","html_url":"https://awesome.ecosyste.ms/projects/github.com%2Fdennisreimann%2FAuthenticationController","lists_url":"https://awesome.ecosyste.ms/api/v1/projects/github.com%2Fdennisreimann%2FAuthenticationController/lists"}