iOS:如何在应用程序中存储用户名/密码?

Kov*_*ovu 274 keychain nsuserdefaults ios

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

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

那么NSUserDefaults将被清除.

但在我的应用程序中,我需要这个用户名/密码用于用户的数据库查询.那么:除了存储数据的位置NSUserDefaults?(当用户退出应用程序或注销时,可以/应该删除此位置).

Fil*_*lic 423

您应该始终使用Keychain来存储用户名和密码,并且由于它是安全存储的,并且只能由您的应用访问,因此无需在应用退出时删除它(如果这是您关注的话).

Apple提供了存储,读取和删除钥匙串项的示例代码,以及如何使用该示例中的钥匙串包装器类,这极大地简化了使用Keychain.

包括Security.framework (在Xcode 3中右键单击frameworks文件夹并添加现有框架.在Xcode 4中选择你的项目,然后选择target,转到Build Phases选项卡并点击Link Binary With Files下的+)和KeychainItemWrapper .h&. m文件到你的项目中,#import你需要使用keychain的.h文件,然后创建这个类的实例:

KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
Run Code Online (Sandbox Code Playgroud)

(YourAppLogin可以是您选择调用钥匙串项目的任何内容,如果需要,您可以拥有多个项目)

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

[keychainItem setObject:@"password you are saving" forKey:kSecValueData];
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];
Run Code Online (Sandbox Code Playgroud)

让他们使用:

NSString *password = [keychainItem objectForKey:kSecValueData];
NSString *username = [keychainItem objectForKey:kSecAttrAccount];
Run Code Online (Sandbox Code Playgroud)

或使用以下方法删除它

[keychainItem resetKeychainItem];
Run Code Online (Sandbox Code Playgroud)

  • 使用ARC时,编译器会因为在Objective-C代码中使用常量`kSecValueData`和`kSecAttrAccount`而大喊大叫,所以一定要使用`(__ bridge id)`来强制转换它们,例如``[keychainItem setObject:obj forKey :(__ bridge id)kSecValueData];` (63认同)
  • ***ATTANTION!***请添加到您的答案,只有"复制KeychainItemWrapper"是不够的!我遇到了问题,事后我无法建立它!您必须将security.framework添加到KeychainItemWrapper将工作的项目中!(HowTo:选择项目 - >选择目标 - >选择选项卡"构建阶段" - >选择"使用Libaries链接二进制" - >"+" - >添加Security.Framework) (44认同)
  • 使用ARC时,Apple已经[在此处](https://developer.apple.com/library/ios/documentation/security/conceptual/keychainServConcepts/iPhoneTasks/iPhoneTasks.html)提供了更新的代码.请看清单2-1.虽然方法是一样的. (12认同)
  • KeychainItemWrapper.m似乎在第196行有内存泄漏.将行更改为"self.keychainItemData = [[[NSMutableDictionary alloc] init] autorelease];" 解决它. (7认同)
  • 我已经用代码和描述更新了我的答案.它并不像你想象的那么难. (5认同)
  • 我尝试了这个解决方案,但是当我重新启动应用程序时,我获得的kSecAttrAccount字符串为空.我已经尝试使用我需要保存的字符串的复制功能,并且还添加了一个@"用户名",但它没有被存储,是否还需要做其他事情? (2认同)

小智 97

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


sus*_*t86 48

通过钥匙串的一个非常简单的解决方案.

它是系统Keychain的简单包装器.就在增加SSKeychain.h,SSKeychain.m,SSKeychainQuery.hSSKeychainQuery.m文件到您的项目,并添加Security.framework你的目标.

要保存密码:

[SSKeychain setPassword:@"AnyPassword" forService:@"AnyService" account:@"AnyUser"]
Run Code Online (Sandbox Code Playgroud)

要检索密码:

NSString *password = [SSKeychain passwordForService:@"AnyService" account:@"AnyUser"];
Run Code Online (Sandbox Code Playgroud)

哪里setPassword是你想要保存,什么价值forService是你想要的变量它救下,并考虑是什么用户/对象的密码和其他信息是.

  • 除了密码之外,你如何存储用户名?如何从SSKeychain中删除整个帐户?两者都没有提到文档 (4认同)
  • 要获取用户名,请执行`NSString*username = [[SSKeychain accountsForService:@"AnyService"] [0] valueForKey:@"acct"]`.如果您只使用一个帐户,这应该可以正常工作.与往常一样,在尝试访问索引0之前,请务必检查数组长度. (2认同)

Phi*_*hil 27

您可以简单地使用NSURLCredential,只需两行代码就可以在钥匙串中保存用户名和密码.

看我详细的答案.


小智 13

我决定使用Obj-C和ARC回答如何在iOS 8中使用keychain.

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

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

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)];
Run Code Online (Sandbox Code Playgroud)

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;
Run Code Online (Sandbox Code Playgroud)

请享用!


小智 11

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

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