2011-03-09 11 views
56

iOS geliştirmede çok yeniyim, bu bir yeni kullanıcı soruysa beni affet. Uygulamamın, kullanıcının e-posta adresini ve şifresini alan basit bir kimlik doğrulama mekanizmasına sahibim. Ayrıca 'Beni hatırla' yazan bir anahtarım var. Kullanıcı bu geçişi değiştirirse, e-postalarını/şifrelerini korumak isterim, böylece bu alanlar gelecekte otomatik olarak doldurulabilir.iOS'ta Anahtar Zincirine E-posta/Şifre Kaydetme

Bunu bir plist dosyasına kaydetme ile çalışmak için aldım ancak şifrenin şifrelenmediğinden beri en iyi fikir olmadığını biliyorum. Anahtarlığa kaydetmek için bazı örnek kodlar buldum, ama dürüst olmak gerekirse, biraz kayboldum. Aşağıdaki işlev için, nasıl arayacağımı ve e-posta adresini de kaydetmek için nasıl değiştirileceğimi bilmiyorum.

öyle olacağını çağırmak tahmin ediyorum: saveString(@"passwordgoeshere");

herhangi bir yardım için teşekkür ederiz !!!

+ (void)saveString:(NSString *)inputString forKey:(NSString *)account { 

    NSAssert(account != nil, @"Invalid account"); 
    NSAssert(inputString != nil, @"Invalid string"); 

    NSMutableDictionary *query = [NSMutableDictionary dictionary]; 

    [query setObject:(id)kSecClassGenericPassword forKey:(id)kSecClass]; 
    [query setObject:account forKey:(id)kSecAttrAccount]; 
    [query setObject:(id)kSecAttrAccessibleWhenUnlocked forKey:(id)kSecAttrAccessible]; 

    OSStatus error = SecItemCopyMatching((CFDictionaryRef)query, NULL); 
    if (error == errSecSuccess) { 
     // do update 
     NSDictionary *attributesToUpdate = [NSDictionary dictionaryWithObject:[inputString dataUsingEncoding:NSUTF8StringEncoding] 
                     forKey:(id)kSecValueData]; 

     error = SecItemUpdate((CFDictionaryRef)query, (CFDictionaryRef)attributesToUpdate); 
     NSAssert1(error == errSecSuccess, @"SecItemUpdate failed: %d", error); 
    } else if (error == errSecItemNotFound) { 
     // do add 
     [query setObject:[inputString dataUsingEncoding:NSUTF8StringEncoding] forKey:(id)kSecValueData]; 

     error = SecItemAdd((CFDictionaryRef)query, NULL); 
     NSAssert1(error == errSecSuccess, @"SecItemAdd failed: %d", error); 
    } else { 
     NSAssert1(NO, @"SecItemCopyMatching failed: %d", error); 
    } 
} 
+5

KeychainUserPass.m (Bu cevaba bağlı ve her iki dosya da kullanıcıyı belirtilen, ancak daha ileri atıf isterseniz lütfen bana bildirin). Biçimlendirmeyi biraz değiştirdim ve yöntem isimlerini biraz daha genel hale getirdim. https://github.com/jeremangnr/JNKeychain – jere

cevap

100

Ben anahtarlığa herhangi NSCoding uyumlu nesnenin tasarruf sağlayan basit bir sarmalayıcı yazdım. Örneğin, e-postanızı ve şifrenizi bir NSDictionary içinde saklayabilir ve bu sınıfı kullanarak NSDictionary'ı anahtarlığa depolayabilirsiniz.

SimpleKeychain.h

#import <Foundation/Foundation.h> 

@class SimpleKeychainUserPass; 

@interface SimpleKeychain : NSObject 

+ (void)save:(NSString *)service data:(id)data; 
+ (id)load:(NSString *)service; 
+ (void)delete:(NSString *)service; 

@end 

SimpleKeychain.m

#import "SimpleKeychain.h" 

@implementation SimpleKeychain 

+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service { 
    return [NSMutableDictionary dictionaryWithObjectsAndKeys: 
      (id)kSecClassGenericPassword, (id)kSecClass, 
      service, (id)kSecAttrService, 
      service, (id)kSecAttrAccount, 
      (id)kSecAttrAccessibleAfterFirstUnlock, (id)kSecAttrAccessible, 
      nil]; 
} 

+ (void)save:(NSString *)service data:(id)data { 
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 
    SecItemDelete((CFDictionaryRef)keychainQuery); 
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(id)kSecValueData]; 
    SecItemAdd((CFDictionaryRef)keychainQuery, NULL); 
} 

+ (id)load:(NSString *)service { 
    id ret = nil; 
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(id)kSecReturnData]; 
    [keychainQuery setObject:(id)kSecMatchLimitOne forKey:(id)kSecMatchLimit]; 
    CFDataRef keyData = NULL; 
    if (SecItemCopyMatching((CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { 
     @try { 
      ret = [NSKeyedUnarchiver unarchiveObjectWithData:(NSData *)keyData]; 
     } 
     @catch (NSException *e) { 
      NSLog(@"Unarchive of %@ failed: %@", service, e); 
     } 
     @finally {} 
    } 
    if (keyData) CFRelease(keyData); 
    return ret; 
} 

+ (void)delete:(NSString *)service { 
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 
    SecItemDelete((CFDictionaryRef)keychainQuery); 
} 

@end 
+0

bu bir osx keycahin için çalışır mı? – abe

+0

@abe: Deneyin ve görüyor musunuz? Belgelere göre, tüm aynı işlevler kullanılabilir, ancak mümkün 'getKeychainQuery:' sözlükte ek parametreler olması gerekir. – Anomie

+0

@Anomie denedim ve değerlerin üzerinde hatalar buldum, bunlardan biri kSecClassGenericPassword ama temel çerçevede destek göründüğü belgelerini kontrol ettim aynı zamanda güvenlik çerçevesini de dahil ettim. thx – abe

38

ARC hazır kod:

KeychainUserPass.h

#import <Foundation/Foundation.h> 

@interface KeychainUserPass : NSObject 

+ (void)save:(NSString *)service data:(id)data; 
+ (id)load:(NSString *)service; 
+ (void)delete:(NSString *)service; 

@end 

Ben ARC ile çalışmak ve Github koymak anomi kodundan @ sabit

#import "KeychainUserPass.h" 

@implementation KeychainUserPass 

+ (NSMutableDictionary *)getKeychainQuery:(NSString *)service { 
    return [NSMutableDictionary dictionaryWithObjectsAndKeys: 
      (__bridge id)kSecClassGenericPassword, (__bridge id)kSecClass, 
      service, (__bridge id)kSecAttrService, 
      service, (__bridge id)kSecAttrAccount, 
      (__bridge id)kSecAttrAccessibleAfterFirstUnlock, (__bridge id)kSecAttrAccessible, 
      nil]; 
} 

+ (void)save:(NSString *)service data:(id)data { 
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 
    SecItemDelete((__bridge CFDictionaryRef)keychainQuery); 
    [keychainQuery setObject:[NSKeyedArchiver archivedDataWithRootObject:data] forKey:(__bridge id)kSecValueData]; 
    SecItemAdd((__bridge CFDictionaryRef)keychainQuery, NULL); 
} 

+ (id)load:(NSString *)service { 
    id ret = nil; 
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 
    [keychainQuery setObject:(id)kCFBooleanTrue forKey:(__bridge id)kSecReturnData]; 
    [keychainQuery setObject:(__bridge id)kSecMatchLimitOne forKey:(__bridge id)kSecMatchLimit]; 
    CFDataRef keyData = NULL; 
    if (SecItemCopyMatching((__bridge CFDictionaryRef)keychainQuery, (CFTypeRef *)&keyData) == noErr) { 
     @try { 
      ret = [NSKeyedUnarchiver unarchiveObjectWithData:(__bridge NSData *)keyData]; 
     } 
     @catch (NSException *e) { 
      NSLog(@"Unarchive of %@ failed: %@", service, e); 
     } 
     @finally {} 
    } 
    if (keyData) CFRelease(keyData); 
    return ret; 
} 

+ (void)delete:(NSString *)service { 
    NSMutableDictionary *keychainQuery = [self getKeychainQuery:service]; 
    SecItemDelete((__bridge CFDictionaryRef)keychainQuery); 
} 

@end 
+3

ARC için teşekkür ederiz hazır versiyon Bir çekicilik gibi çalışır. –

+0

Sorun değil :) –

+0

kusursuz, thx !! – mnl