我的iOS应用程序中有一个登录屏幕。
用户名和密码将保存在NSUserDefaults中,并在再次进入该应用程序时再次加载到登录屏幕中(当然,NSUserDefaults是永久的)。

现在,用户可以禁用用户名/密码保存功能。

因此NSUserDefaults将被清除。

但是在我应用程序我需要此用户名/密码来进行用户数据库查询。
所以:除NSUserDefaults之外,数据存储在哪里?
(当用户退出应用或注销时,可以/应该删除此地方)。

评论

用户只能通过重置设备或删除应用程序来清除它。我想念什么吗?

顺便说一句,如果用户退出应用程序时应该删除数据,为什么不只是将其保存在RAM中?

您应该认真考虑使用Keychain而不是NSUserDefaults来存储用户名和密码。

您可以从此处获得关于swift3实现的基本想法

请问我应该始终使用kSecValueData和kSecValueData作为键吗?还是可以将任何字符串用作键?

#1 楼

您应该始终使用钥匙串来存储用户名和密码,并且由于它安全地存储并且只能由您的应用访问,因此在应用退出时无需删除它(如果您对此感到担忧)。

Apple提供存储,读取和删除钥匙串项目的示例代码,这是如何使用该示例中的钥匙串包装器类,从而大大简化了使用钥匙串的过程。

包括Security.framework(在Xcode 3中,右键单击在Xcode 4中选择您的项目,然后选择目标,转到Build Phases选项卡,然后单击Link Binary With Files下的+,然后将KeychainItemWrapper .h和.m文件导入您的项目,#import .h文件任何需要使用钥匙串然后创建此类的实例的地方:

KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];


(YourAppLogin可以是您选择调用钥匙串项的任何项,并且可以有多个项

然后可以使用以下命令设置用户名和密码:

q4312 078q

使用以下方法获取它们:

[keychainItem setObject:@"password you are saving" forKey:kSecValueData];
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];


或使用以下方法删除它们:

NSString *password = [keychainItem objectForKey:kSecValueData];
NSString *username = [keychainItem objectForKey:kSecAttrAccount];


评论


我已经用代码和说明更新了答案。这并不像您想的那么难。

–Filip Radelic
11年8月7日在11:18

吸引力!请补充您的答案,仅“复制KeychainItemWrapper”是不够的!我有一个问题,那就是以后无法构建!您必须将security.framework添加到KeychainItemWrapper可以使用的项目中! (操作方法:选择项目->选择目标->选择选项卡“构建阶段”->选择“使用库链接二进制文件”->“ +”->添加Security.Framework)

– PassionateDeveloper
2011年8月7日在17:20

使用ARC时,编译器会对在Objective-C代码中使用常量kSecValueData和kSecAttrAccount喊叫您,因此请务必使用(__bridge id)强制转换它们,例如[keychainItem setObject:obj forKey:(__ bridge id)kSecValueData] ;

–乔·汉金(Joe Hankin)
13-4-6在23:13



KeychainItemWrapper.m似乎在第196行出现内存泄漏。将该行更改为“ self.keychainItemData = [[[[NSMutableDictionary alloc] init] autorelease];”。解决它。

–牛头
2013年6月17日12:33

使用ARC时,Apple已在此处提供了更新的代码。看清单2-1。虽然方法是相同的。

–里克
2014年8月26日12:35



#2 楼

如果您需要ARC版本的包装器,请点击以下链接https://gist.github.com/1170641
感谢

评论


谢谢,我从该URL获得KeychainItemWrapper .h和.m。

–Parthpatel1105
18年1月29日在2:46

#3 楼

通过钥匙串非常简单的解决方案。

它是系统钥匙串的简单包装。只需将SSKeychain.hSSKeychain.mSSKeychainQuery.hSSKeychainQuery.m文件添加到项目中,然后将Security.framework添加到目标即可。

要保存密码:

[SSKeychain setPassword:@"AnyPassword" forService:@"AnyService" account:@"AnyUser"]


要检索密码:

NSString *password = [SSKeychain passwordForService:@"AnyService" account:@"AnyUser"];


setPassword是要保存的值,forService是要保存在其下的变量,帐户是针对哪个用户的/ object密码和其他任何信息。

评论


您知道如何使用sskeychain来同步具有相同用户名和密码的应用程序吗?

– Joe Shamuraq
13年3月27日在16:36

除了密码,您还如何存储用户名?如何从SSKeychain删除整个帐户?两者都没有提到文档

–user798719
2013年9月9日18:57

要获取用户名,请执行NSString * username = [[SSKeychain accountsForService:@“ AnyService”] [0] valueForKey:@“ acct”]。如果您仅使用一个帐户,这应该可以正常工作。与往常一样,请确保在尝试访问索引0之前检查数组长度。

–讨厌的价格
2014年6月12日下午16:26

#4 楼

您只需使用NSURLCredential,它只需两行代码即可将用户名和密码保存在钥匙串中。

请参阅我的详细答案。

#5 楼

我决定回答如何使用Obj-C和ARC在iOS 8中使用钥匙串。

1)我使用了GIST的keychainItemWrapper(ARCifief版本):
https://gist.github .com / dhoerl / 1170641 / download
-将KeychainItemWrapper.h和.m添加(+复制)到您的项目中

2)将Security框架添加到您的项目中(在项目中签入>构建阶段>使用库链接二进制文件)

3)将安全性库(#import)和KeychainItemWrapper(#import“ KeychainItemWrapper.h”)添加到要使用的.h和.m文件中

4)要将数据保存到钥匙串:

NSString *emailAddress = self.txtEmail.text;
NSString *password = self.txtPasword.text;
//because keychain saves password as NSData object
NSData *pwdData = [password dataUsingEncoding:NSUTF8StringEncoding];

//Save item
self.keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
[self.keychainItem setObject:emailAddress forKey:(__bridge id)(kSecAttrAccount)];
[self.keychainItem setObject:pwdData forKey:(__bridge id)(kSecValueData)];


5)读取数据(可能是加载时的登录屏幕> viewDidLoad):

self.keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];

self.txtEmail.text = [self.keychainItem objectForKey:(__bridge id)(kSecAttrAccount)];

//because label uses NSString and password is NSData object, conversion necessary
NSData *pwdData = [self.keychainItem objectForKey:(__bridge id)(kSecValueData)];
NSString *password = [[NSString alloc] initWithData:pwdData encoding:NSUTF8StringEncoding];
self.txtPassword.text = password;


享受吧!

#6 楼

如果您在使用钥匙串包装器检索密码时遇到问题,请使用以下代码:

NSData *pass =[keychain objectForKey:(__bridge id)(kSecValueData)];
NSString *passworddecoded = [[NSString alloc] initWithData:pass
                                           encoding:NSUTF8StringEncoding];


#7 楼

检出此示例代码
我首先尝试了示例代码中的苹果包装纸,但这对我来说要简单得多

#8 楼

试试这个:

 KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
[keychainItem setObject:@"password you are saving" forKey:kSecValueData]; 
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];


可能会有所帮助。

#9 楼

我看过使用KeychainItemWrapper(ARC版本),但没有找到理想的目标C包装器。

我使用Kishikawa Katsumi的此解决方案,这意味着我编写了更少的代码,而没有不必使用强制转换来存储NSString值。

两个存储示例:

[UICKeyChainStore setString:@"kishikawakatsumi" forKey:@"username"];
[UICKeyChainStore setString:@"P455_w0rd$G$Z$" forKey:@"password"];


两个检索示例

UICKeyChainStore *store = [UICKeyChainStore keyChainStore];
    // or
UICKeyChainStore *store = [UICKeyChainStore keyChainStoreWithService:@"YOUR_SERVICE"];

NSString *username = [store stringForKey:@"username"];
NSString *password = [store stringForKey:@"password"];


#10 楼

上面的代码中有一个小错误(顺便说一句,戴夫对您的帖子非常有帮助,谢谢您)

在保存凭据的部分中,它还需要以下代码才能正常工作。

[self.keychainItem setObject:@"myCredentials" forKey:(__bridge id)(kSecAttrService)];


最可能是因为我们第二次尝试使用相同的凭据登录(重新),发现它们已在钥匙串项中分配,并且应用程序崩溃。使用上面的代码,它就像一个魅力。

#11 楼

要更新此问题:

对于那些使用Swift签出的用户,Mihai Costea支持访问组的拖放式swift实现:

https://github.com/macostea/KeychainItemWrapper .swift / blob / master / KeychainItemWrapper.swift

在使用钥匙串之前:
在存储密码之前要考虑两次。在许多情况下,存储身份验证令牌(例如持久性会话ID)以及电子邮件或帐户名可能就足够了。您可以轻松地使身份验证令牌无效,以阻止未经授权的访问,这要求用户再次在受感染的设备上登录,而又不需要重置密码,而必须在所有设备上再次登录(我们不仅使用Apple,还使用Apple吗?)。

#12 楼

但是,现在您可以使用NURLCredential而不是钥匙串包装器了。它完成了我们需要做的。

#13 楼

对于swift,您可以使用以下库:

https://github.com/jrendel/SwiftKeychainWrapper

它支持swift的所有版本。

#14 楼

以下应该可以正常工作:

KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
[keychainItem setObject:@"password you are saving" forKey:kSecValueData]; 
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];