iOS:如何在应用程序中存储用户名/密码?
Posted
技术标签:
【中文标题】iOS:如何在应用程序中存储用户名/密码?【英文标题】:iOS: How to store username/password within an app? 【发布时间】:2011-10-21 18:34:37 【问题描述】:我的 ios 应用中有一个登录屏幕。
用户名和密码将保存在NSUserDefaults
中,并在您再次进入应用程序时再次加载到登录屏幕(当然,NSUserDefaults
是永久的)。
现在,用户可以禁用用户名/密码保存功能。
所以NSUserDefaults
将被清除。
但是在我的应用程序中,我需要这个用户名/密码来为用户进行数据库查询。
那么:除了NSUserDefaults
之外的数据存储在哪里?
(这个地方可以/应该在用户退出应用程序或注销时删除)。
【问题讨论】:
用户只能通过重置设备或删除应用程序来清除它。我错过了什么吗? 顺便说一句,如果数据应该在用户退出应用程序时被删除,为什么不将其保留在 RAM 中? 你应该认真考虑使用 Keychain 来存储用户名和密码,而不是 NSUserDefaults。 你可以从here获得关于swift3实现的基本思路 请问我应该始终使用 kSecValueData 和 kSecValueData 作为键吗?或者我可以使用任何字符串作为键吗? 【参考方案1】:如果您的应用有关联的域,最好使用Managing Shared Credentials。它将为用户提供最佳体验,并由系统本身管理。
第 1 步:
使用 webcredentials 密钥设置您的 Associated Domains
第 2 步
标记您的文本字段
userIdTextField.textContentType = .username
passwordTextField.textContentType = .password
第 3 步
只要用户成功登录,请使用以下代码保存详细信息。 iOS 将显示一个确认操作表供用户保存密码。下次用户尝试登录时,键盘会提示您应用的用户凭据。
SecAddSharedWebCredential("www.example.com" as CFString, "user_id" as CFString, "password" as CFString) error in
if error != nil
// Handle error
return
// The credentials have been successfully saved.
现在你准备好了。 Read more...?!
【讨论】:
【参考方案2】:您可以简单地使用NSURLCredential
,它会仅用两行代码将用户名和密码保存在钥匙串中。
查看我的详细信息answer。
【讨论】:
【参考方案3】:我决定回答如何使用 Obj-C 和 ARC 在 iOS 8 中使用钥匙串。
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)];
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;
享受吧!
【讨论】:
【参考方案4】:你可以使用这个库来快速运行:
https://github.com/jrendel/SwiftKeychainWrapper
它支持所有版本的swift。
【讨论】:
【参考方案5】:但是,现在您可以使用 NURLCredential 而不是钥匙串包装器。它完成了我们需要做的事情。
【讨论】:
【参考方案6】:Keychains 的一个非常简单的解决方案。
它是系统钥匙串的简单包装器。只需将 SSKeychain.h
、SSKeychain.m
、SSKeychainQuery.h
和 SSKeychainQuery.m
文件添加到您的项目中,并将 Security.framework 添加到您的目标中。
保存密码:
[SSKeychain setPassword:@"AnyPassword" forService:@"AnyService" account:@"AnyUser"]
要找回密码:
NSString *password = [SSKeychain passwordForService:@"AnyService" account:@"AnyUser"];
setPassword
是您希望保存的值,forService
是您希望将其保存在哪个变量下,而 account 是用于密码和任何其他信息的用户/对象。
【讨论】:
你知道如何使用 sskeychain 来同步相同用户名和密码的应用吗? 除了密码之外,您还如何存储用户名?如何从 SSKeychain 中删除整个帐户?两者都没有提到文档 要获取用户名,请执行NSString *username = [[SSKeychain accountsForService:@"AnyService"][0] valueForKey:@"acct"]
。如果您只使用一个帐户,这应该可以正常工作。与往常一样,请务必在尝试访问索引 0 之前检查数组长度。【参考方案7】:
更新这个问题:
对于那些使用 Swift 的用户,请查看 Mihai Costea 支持访问组的拖放式快速实现:
https://github.com/macostea/KeychainItemWrapper.swift/blob/master/KeychainItemWrapper.swift
使用钥匙串之前: 在存储密码之前考虑两次。在许多情况下,存储身份验证令牌(例如持久会话 ID)和电子邮件或帐户名称可能就足够了。您可以轻松地使身份验证令牌无效以阻止未经授权的访问,要求用户在受感染的设备上重新登录,但不需要重置密码,并且必须在所有设备上重新登录(我们不仅使用 Apple 吗?)。
【讨论】:
【参考方案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】:上面的代码有一个小错误(顺便说一句,Dave 对你的帖子很有帮助,谢谢)
在我们保存凭据的部分,它还需要以下代码才能正常工作。
[self.keychainItem setObject:@"myCredentials" forKey:(__bridge id)(kSecAttrService)];
很可能是因为我们第二次尝试(重新)使用相同的凭据登录时,它发现它们已经在钥匙串项目中分配并且应用程序崩溃了。使用上面的代码,它就像一个魅力。
【讨论】:
【参考方案10】:我查看了使用 KeychainItemWrapper(ARC 版本),但我没有发现它的 Objective C 包装器符合预期。
我使用this solution by Kishikawa Katsumi,这意味着我编写的代码更少,并且不必使用强制转换来存储 NSString 值。
存储的两个例子:
[UICKeyChainStore setString:@"kishikawakatsumi" forKey:@"username"];
[UICKeyChainStore setString:@"P455_w0rd$1$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"];
【讨论】:
【参考方案11】:您应该始终使用 Keychain 来存储用户名和密码,并且由于它是安全存储的并且只有您的应用可以访问,因此无需在应用退出时将其删除(如果您担心的话)。
Apple 提供了 sample code 来存储、读取和删除钥匙串项,这里是如何使用该示例中的钥匙串包装类,这极大地简化了钥匙串的使用。
包含 Security.framework (在 Xcode 3 中右键单击 frameworks 文件夹并添加现有框架。在 Xcode 4 中选择您的项目,然后选择目标,转到 Build Phases 选项卡并单击 Link Binary With Files 下的 +) 和 KeychainItemWrapper .h & .m 文件到你的项目中,#import .h 文件到你需要使用钥匙串的地方,然后创建这个类的一个实例:
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
(YourAppLogin 可以是您选择调用钥匙串项的任何内容,如果需要,您可以拥有多个项)
然后您可以使用以下方式设置用户名和密码:
[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];
或使用以下方法删除它们:
[keychainItem resetKeychainItem];
【讨论】:
我已经用代码和描述更新了我的答案。这并不像你想象的那么难。 ATTANTION! 请添加到您的答案中,仅“复制 KeychainItemWrapper”是不够的!我遇到了问题,之后我无法构建它!您必须将 security.framework 添加到 KeychainItemWrapper 才能工作的项目中! (操作方法:选择项目 -> 选择目标 -> 选择选项卡“构建阶段” -> 选择“使用库链接二进制文件” -> “+” -> 添加 Security.Framework) 使用 ARC 时,编译器会因为你在 Objective-C 代码中使用常量kSecValueData
和 kSecAttrAccount
而大喊大叫,所以一定要使用 (__bridge id)
进行转换,例如,@987654330 @
KeychainItemWrapper.m 似乎在第 196 行有内存泄漏。将行更改为“self.keychainItemData = [[[NSMutableDictionary alloc] init] autorelease];”修复它。
使用 ARC 时,Apple 已提供更新的代码here。请看清单 2-1。虽然方法是一样的。【参考方案12】:
如果您在使用钥匙串包装器检索密码时遇到问题,请使用以下代码:
NSData *pass =[keychain objectForKey:(__bridge id)(kSecValueData)];
NSString *passworddecoded = [[NSString alloc] initWithData:pass
encoding:NSUTF8StringEncoding];
【讨论】:
【参考方案13】:试试这个:
KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
[keychainItem setObject:@"password you are saving" forKey:kSecValueData];
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];
可能会有所帮助。
【讨论】:
【参考方案14】:查看此sample code 我首先从示例代码中尝试了苹果的包装器,但这对我来说要简单得多
【讨论】:
【参考方案15】:如果您需要 ARC 版本的包装器,请点击链接 https://gist.github.com/1170641 感谢
【讨论】:
谢谢,我从那个 URL 得到 KeychainItemWrapper .h & .m。以上是关于iOS:如何在应用程序中存储用户名/密码?的主要内容,如果未能解决你的问题,请参考以下文章