我对iOS开发非常陌生,所以如果这是一个新手问题,请原谅。我的应用程序有一个简单的身份验证机制,可以接受用户的电子邮件地址和密码。我还有一个开关,上面写着“记住我”。如果用户打开该开关,我希望保留他们的电子邮件/密码,以便将来可以自动填充这些字段。
我已经让它保存到plist文件,但我知道这不是最好的主意,因为密码是未加密的。我找到了一些保存到keychain的示例代码,但老实说,我有点迷路了。对于下面的函数,我不确定如何调用它,以及如何修改它来保存电子邮件地址。
我猜应该是:saveString(@"passwordgoeshere");
感谢您的帮助!
+ (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);
}
}
发布于 2013-11-24 16:14:04
准备好ARC的代码:
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
KeychainUserPass.m
#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
发布于 2021-04-25 21:03:37
我不认为你建议的方法是做一个‘记住我’功能的好方法。我认为更好的方法是不将该用户从其在服务器上的帐户注销。在客户端存储一个带有散列值的cookie,并在每次服务器调用时发送该cookie。无论如何,您应该始终对每个服务器调用执行此操作,而不是发送本地存储的密码。甚至不要将它们存储在局部变量中。
如果用户想要将密码存储在它的钥匙链上,这与“记住我”是完全不同的、独立的用户任务。我担心您混淆了这两个用例。
https://stackoverflow.com/questions/5247912
复制相似问题