首页
学习
活动
专区
工具
TVP
发布
社区首页 >问答首页 >将电子邮件/密码保存到iOS中的钥匙链

将电子邮件/密码保存到iOS中的钥匙链
EN

Stack Overflow用户
提问于 2011-03-09 23:20:51
回答 2查看 32.8K关注 0票数 56

我对iOS开发非常陌生,所以如果这是一个新手问题,请原谅。我的应用程序有一个简单的身份验证机制,可以接受用户的电子邮件地址和密码。我还有一个开关,上面写着“记住我”。如果用户打开该开关,我希望保留他们的电子邮件/密码,以便将来可以自动填充这些字段。

我已经让它保存到plist文件,但我知道这不是最好的主意,因为密码是未加密的。我找到了一些保存到keychain的示例代码,但老实说,我有点迷路了。对于下面的函数,我不确定如何调用它,以及如何修改它来保存电子邮件地址。

我猜应该是:saveString(@"passwordgoeshere");

感谢您的帮助!

代码语言:javascript
复制
+ (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);
    }
}
EN

回答 2

Stack Overflow用户

发布于 2013-11-24 16:14:04

准备好ARC的代码:

KeychainUserPass.h

代码语言:javascript
复制
#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

代码语言:javascript
复制
#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
票数 39
EN

Stack Overflow用户

发布于 2021-04-25 21:03:37

我不认为你建议的方法是做一个‘记住我’功能的好方法。我认为更好的方法是不将该用户从其在服务器上的帐户注销。在客户端存储一个带有散列值的cookie,并在每次服务器调用时发送该cookie。无论如何,您应该始终对每个服务器调用执行此操作,而不是发送本地存储的密码。甚至不要将它们存储在局部变量中。

如果用户想要将密码存储在它的钥匙链上,这与“记住我”是完全不同的、独立的用户任务。我担心您混淆了这两个用例。

票数 0
EN
页面原文内容由Stack Overflow提供。腾讯云小微IT领域专用引擎提供翻译支持
原文链接:

https://stackoverflow.com/questions/5247912

复制
相关文章

相似问题

领券
问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档