iOS - 如何使用钥匙串/核心数据创建登录过程?

Posted

技术标签:

【中文标题】iOS - 如何使用钥匙串/核心数据创建登录过程?【英文标题】:iOS - How to create a login process using keychain / Core Data? 【发布时间】:2012-06-25 17:02:12 【问题描述】:

我正在创建一个多用户 iPhone 应用程序,并且我正在尝试完成用户登录过程的编码。我可以成功创建一个帐户,并将用户输入的数据存储到 Core Data DB 中,并将 pin(密码)存储到 Keychain 中,所以现在我正在尝试完成登录过程。下面列出的以下代码是我到目前为止所拥有的,我想知道我需要做什么才能完成登录过程。

- (IBAction)processLogin:(id)sender 

// hide keyboard
[_textFieldUsername resignFirstResponder];
[_textFieldPin resignFirstResponder];


// First - make activity indicator visible, then start animating, then turn of wrong user / pin label
_welcomeActivityIndicator.hidden = FALSE;
[_welcomeActivityIndicator startAnimating];
[_wrongUserPin setHidden:YES];

// check if username and pin text fields are populated
if ([_textFieldUsername.text length ] == 0 &&  [_textFieldPin.text length ] == 0)

    [_welcomeActivityIndicator stopAnimating];
    [_wrongUserPin setHidden:NO];   


// CORE DATA    
NSFetchRequest *request= [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Account" inManagedObjectContext:_managedObjectContext];
NSPredicate *predicate =[NSPredicate predicateWithFormat:@"username=%@",self.textFieldUsername.text];

//check pin
Account *pinAccount = [[Account alloc] init];
[pinAccount.password isEqualToString:_textFieldPin.text];

[request setEntity:entity];
[request setPredicate:predicate];

NSError *error = nil;

NSArray *array = [_managedObjectContext executeFetchRequest:request error:&error];
if (array != nil) 
    NSUInteger count = [array count]; // may be 0 if the object has been deleted.
    NSLog(@"Username may exist, %@",count);


else 
    NSLog(@"Username does not exist.");


// TODO - put this in proper place - play audio bell if user logs in correctly
CFBundleRef mainBundle = CFBundleGetMainBundle();
CFURLRef soundFileURLRef;
soundFileURLRef = CFBundleCopyResourceURL(mainBundle, (CFStringRef) @"Glass", CFSTR("aiff"), NULL);
UInt32 soundID;
AudioservicesCreateSystemSoundID(soundFileURLRef, &soundID);
AudioServicesPlaySystemSound(soundID);

// TODO - put this in proper place - Load ViewControllerHome
UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
ViewControllerHome *home = (ViewControllerHome *)[storyboard instantiateViewControllerWithIdentifier:@"Home"];
[self presentModalViewController:home animated:YES];


AccountAccountBase 类文件 mh 如下所示:

Account.h http://pastie.org/4149299

Account.m http://pastie.org/4149296

AccountBase.h http://pastie.org/4149301

AccountBase.m http://pastie.org/4149302

如果有任何想法或想法,我将不胜感激,并感谢您的阅读。

【问题讨论】:

【参考方案1】:

我能够使用以下代码完成登录过程。

- (IBAction)processLogin:(id)sender 

// hide keyboard
[_textFieldUsername resignFirstResponder];
[_textFieldPin resignFirstResponder];


// First - make activity indicator visible, then start animating, then turn of wrong user / pin label
_welcomeActivityIndicator.hidden = FALSE;
[_welcomeActivityIndicator startAnimating];
[_wrongUserPin setHidden:YES];

// check if username and pin text fields are populated
if ([_textFieldUsername.text length ] == 0 &&  [_textFieldPin.text length ] == 0)

    [_welcomeActivityIndicator stopAnimating];
    [_wrongUserPin setHidden:NO];   


// CORE DATA
NSFetchRequest *request = [[NSFetchRequest alloc] init];
NSEntityDescription *entity = [NSEntityDescription entityForName:@"Account" inManagedObjectContext:_managedObjectContext];

// set entity for request
[request setEntity:entity];

// filter results using a predicate
NSPredicate *pred =[NSPredicate predicateWithFormat:(@"username = %@"), _textFieldUsername.text];

// set predicate for the request
[request setPredicate:pred];

NSError *error = nil;

// store DB usernames in results array
NSArray *results = [_managedObjectContext executeFetchRequest:request error:&error];

NSLog(@"The returned results are %@",results);


// check text field against results stored in DB
for (Account *anAccount in results) 
    if ([anAccount.username isEqualToString:_textFieldUsername.text])
        NSLog(@"Your username exists");
        if ([anAccount.password isEqualToString:_textFieldPin.text])
            NSLog(@"Your pin is correct");

            // TODO - put this in proper place - play audio bell if user logs in correctly
            CFBundleRef mainBundle = CFBundleGetMainBundle();
            CFURLRef soundFileURLRef;
            soundFileURLRef = CFBundleCopyResourceURL(mainBundle, (CFStringRef) @"Glass", CFSTR("aiff"), NULL);
            UInt32 soundID;
            AudioServicesCreateSystemSoundID(soundFileURLRef, &soundID);
            AudioServicesPlaySystemSound(soundID);

            // TODO - put this in proper place - Load ViewController(Root)Home
            if([anAccount.username isEqualToString:@"root"])
            
                UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
                ViewControllerRootHome *roothome = (ViewControllerRootHome *)[storyboard instantiateViewControllerWithIdentifier:@"rootHome"];
                [self presentModalViewController:roothome animated:YES];
            
            else 
                UIStoryboard *storyboard = [UIStoryboard storyboardWithName:@"MainStoryboard" bundle:nil];
                ViewControllerHome *home = (ViewControllerHome *)[storyboard instantiateViewControllerWithIdentifier:@"Home"];
                [self presentModalViewController:home animated:YES];
            
        
        else 
            NSLog(@"Your pin is wrong");
            [_welcomeActivityIndicator stopAnimating];
            [_wrongUserPin setHidden:NO];
            
        
    else 
        NSLog(@"Your username was not found");
        [_welcomeActivityIndicator stopAnimating];
        [_wrongUserPin setHidden:NO];
        
    


【讨论】:

【参考方案2】:

我相信您滥用核心数据。它并不像 sqlite 那样使用,始终运行始终可查询。 (http://cocoawithlove.com/2010/02/differences-between-core-data-and.html)

您正在尝试保留用户数据库,但也过于复杂。在内存中,应用程序可以使用您自己的对象的NSMutableArray 来跟踪用户名、标签

所以你会有你的课:

interface Alcoholic : NSObject

@property(nonatomic,retain)NSString * username;
@property(nonatomic,retain)NSString * pin;
@property(nonatomic,retain)NSString * tab;
@end

在添加这些的代码部分中,它会有一个可变数组

 NSMutableArray * alcoholics = [[NSMutableArray alloc]init];

- (IBAction)processLogin:(id)sender 

int i = 0;
while (i<alcoholics.count)

 Aloholic = [alcoholics objectAtIndex:i];
if(self.textFieldUsername.text == Aloholic.username)
   NSLog(@"Username may exist, %@",count);


else 
    NSLog(@"Username does not exist.");


等等……

因为我确定您的下一个问题是如何使其持久化,这就是核心数据发挥作用的地方。

在您的应用委托中获取酒鬼数组并在应用打开和关闭时将其保存到核心数据

-(void)save

     //use core data to save needed data persitently

     self.Values = [NSEntityDescription
                       insertNewObjectForEntityForName:@"processLoginClass" 
                       inManagedObjectContext:[self managedObjectContext]];

          self.Values.alcoholics =  self.processLoginClass.alcoholics;

     

     NSError *error;
     if (![[self managedObjectContext] save:&error]) 
     
          NSLog(@"Couldn't save state information: %@", [error localizedDescription]);
     


-(void)load

     //use core data to load needed data 

     NSError *error;
     NSFetchRequest *fetchRequest = [[NSFetchRequest alloc] init];
     NSEntityDescription *entity = [NSEntityDescription entityForName:@"Values" 
                                               inManagedObjectContext:[self managedObjectContext]];
     [fetchRequest setEntity:entity];

     NSArray *fetchedObjects = [[self managedObjectContext] executeFetchRequest:fetchRequest error:&error];
     for (processLoginClass *info in fetchedObjects) 
     
          [self.processLoginClass setAlcholics:info.alcholics];
           

【讨论】:

以上是关于iOS - 如何使用钥匙串/核心数据创建登录过程?的主要内容,如果未能解决你的问题,请参考以下文章

如何使用钥匙串验证用户名和密码

苹果密码钥匙串在哪里

数据保护、钥匙串和核心数据的 Sqlite 文件

检索钥匙串中的数据以获取在 ios 中不起作用的特定服务

如何在 iOS 应用程序之间共享钥匙串数据

Mac钥匙串有啥用?钥匙串访问是啥