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

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

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

因此NSUserDefaults将被清除。

但是在我的应用程序中,我需要这个用户名/密码用于用户的数据库查询。 那么:除了NSUserDefaults之外,在哪里存储数据? (这个地方可以/应该在用户退出应用程序或登出时删除)
181906 次浏览

你应该总是使用钥匙链来存储用户名和密码,因为它是安全存储的,只对你的应用程序访问,没有必要在应用程序退出时删除它(如果这是你的担心)。

Apple提供了示例代码来存储、读取和删除keychain项,下面是如何从该示例中使用keychain包装器类,这极大地简化了keychain的使用。

包含Security.framework (在Xcode 3中右键单击frameworks文件夹并添加已有的框架。在Xcode 4中选择你的项目,然后选择目标,选择Build Phases选项卡,在链接二进制文件下点击+)和KeychainItemWrapper .h &.m文件到你的项目中,#导入.h文件到任何你需要使用keychain的地方,然后创建这个类的实例:

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];

签出示例代码 我首先从示例代码中尝试了苹果的包装器,但这对我来说更简单

如果你需要一个ARC版本的包装器,这里是链接https://gist.github.com/1170641 感谢

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

它是系统Keychain的一个简单包装。只需将SSKeychain.hSSKeychain.mSSKeychainQuery.hSSKeychainQuery.m文件添加到项目中,并将Security.framework添加到目标中。

保存密码:

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

查询密码。

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

其中setPassword是你想要保存的值,forService是你想要保存的变量,account是用户/对象的密码和其他信息。

你可以简单地使用NSURLCredential,它将在两行代码中保存用户名和密码

请参阅我的详细回答

试试这个:

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

希望它能有所帮助。

我尝试使用KeychainItemWrapper (ARC版本),但我发现它的Objective C包装器不如预期的那么健康。

我使用这个解决方案 by Kishikawa克己,这意味着我写的代码更少,不必使用类型转换来存储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"];

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

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

下面的代码应该可以正常工作:

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

我决定用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")添加到你想使用keychain的.h和.m文件中。

4)保存数据到keychain:

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;

享受吧!

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

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

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

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

更新这个问题:

对于那些使用Swift签出的人来说,Mihai Costea支持的拖放Swift实现访问组:

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

使用keychain前: 存储密码前要三思。在许多情况下,存储一个身份验证令牌(例如持久性会话id)和电子邮件或帐户名可能就足够了。您可以很容易地使身份验证令牌无效以阻止未经授权的访问,要求用户在受损害的设备上再次登录,但不需要重置密码,并且必须在所有设备上再次登录(我们不仅使用Apple,不是吗?)

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

对于swift,你可以使用这个库:

https://github.com/jrendel/SwiftKeychainWrapper

它支持所有版本的swift。

如果你的应用有一个相关的域,最好使用管理共享凭证。它将为用户提供最好的体验,并由系统本身进行管理。

步骤1:

使用webcredentials键设置你的相关的领域

步骤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.
}

现在你准备好了。 阅读更多… ? !< / p >