iOS:アプリ内にユーザー名/パスワードを保存する方法は?


276

iOSアプリにログイン画面があります。ユーザー名とパスワードはに保存NSUserDefaultsされ、再びアプリに入るとログイン画面に再度読み込まれます(もちろんNSUserDefaults永続的です)。

これで、ユーザーはユーザー名/パスワードの保存機能を無効にすることができます。

ですから、それNSUserDefaultsはクリアされます。

しかし、私のアプリでは、ユーザーのデータベースクエリにこのユーザー名/パスワードが必要です。だから:どこにデータを保存するのNSUserDefaultsですか?(この場所は、ユーザーがアプリを終了するか、ログアウトするときに削除できます)。


ユーザーは、デバイスをリセットするか、アプリを削除することによってのみクリアできます。何か不足していますか?

3
ちなみに、ユーザーがアプリを終了したときにデータを削除する必要がある場合は、RAMに保存しないでください。

10
NSUserDefaultsの代わりに、ユーザー名とパスワードの保存にキーチェーンを使用することを真剣に検討する必要があります。
Filip Radelic 2011


キーとして常にkSecValueDataとkSecValueDataを使用する必要がありますか?または、キーとして任意の文字列を使用できますか?
Ne AS

回答:


424

ユーザー名とパスワードの保存には常にキーチェーンを使用する必要があります。キーチェーンは安全に保存され、アプリにのみアクセスできるため、アプリが終了したときにキーチェーンを削除する必要はありません(それが問題であった場合)。

Appleは、キーチェーンアイテムを格納、読み取り、削除するサンプルコードを提供しています。ここでは、そのサンプルのキーチェーンラッパークラスを使用して、キーチェーンの使用を大幅に簡素化する方法を示します。

Security.framework (Xcode 3でフレームワークフォルダーを右クリックし、既存のフレームワークを追加します。Xcode4でプロジェクトを選択し、ターゲットを選択して、[ビルドフェーズ]タブに移動し、[ファイルバイナリをリンク]の下の[+]とKeychainItemWrapper .h&を含めます。プロジェクトにmファイル、#keychainを使用する必要がある場所に.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];

5
コードと説明で回答を更新しました。思ったほど難しくはありません。
Filip Radelic、2011

44
注意!「KeychainItemWrapperをコピーする」だけでは不十分であることを回答に追加してください!後で作成できないという問題がありました!KeychainItemWrapperが機能するように、プロジェクトにsecurity.frameworkを追加する必要があります。(ハウツー:プロジェクトの選択->ターゲットの選択-> [ビルドフェーズ]タブの選択-> [ライブラリとバイナリをリンク]を選択-> "+"-> Security.Frameworkを追加)
Kovu

63
ARCを使用する場合、コンパイラーは定数kSecValueDatakSecAttrAccountObjective-Cコードを使用することを叫ぶので、必ずを使用してそれらをキャストしてください(__bridge id)。例: [keychainItem setObject:obj forKey:(__bridge id)kSecValueData];
Joe Hankin

7
KeychainItemWrapper.mの196行目でメモリリークが発生しているようです。この行を「self.keychainItemData = [[[NSMutableDictionary alloc] init] autorelease];」に変更します。それを修正します。
オロフ2013年

12
ARCを使用する場合、更新されたコードはApple から提供れています。リスト2-1を見てください。アプローチは同じですが。
リック、


48

キーチェーンによる非常に簡単なソリューション。

これは、システムキーチェーンの単純なラッパーです。ただ、追加SSKeychain.hSSKeychain.mSSKeychainQuery.hおよびSSKeychainQuery.mプロジェクトにファイルをして、ターゲットにSecurity.frameworkを追加します。

パスワードを保存するには:

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

パスワードを取得するには:

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

どこにsetPasswordあなたが保存したいものの値ですforServiceあなたはそれを下に保存され、アカウントたい変数は、パスワードやその他の情報が何のためにあるのか、ユーザー/オブジェクトのためにあるものです。


sskeychainを使用して、同じユーザー名とパスワードでアプリを同期する方法を知っていますか?
Joe Shamuraq 2013年

4
パスワードに加えてユーザー名もどのように保存しますか?SSKeychainからアカウント全体を削除するにはどうすればよいですか?どちらもドキュメントには記載されていません
user798719

2
ユーザー名を取得するには、を実行しますNSString *username = [[SSKeychain accountsForService:@"AnyService"][0] valueForKey:@"acct"]。アカウントを1つしか使用しない場合、これは問題なく機能します。いつものように、アクセスのインデックス0にしようとする前に、配列の長さを確認してください
ジャレド価格

27

あなたは単に使うことができますNSURLCredential、それはたった2行のコードでキーチェーンにユーザー名とパスワードの両方保存します

詳細な回答をご覧ください。


13

Obj-CとARCを使用してiOS 8でキーチェーンを使用する方法に答えることに決めました。

1)GISTのkeychainItemWrapper(ARCifiefバージョン)を使用しました:https ://gist.github.com/dhoerl/1170641/download-KeychainItemWrapper.h と.mをプロジェクトに追加(+コピー)します

2)プロジェクトにセキュリティフレームワークを追加します(プロジェクトをチェックイン>ビルドフェーズ>ライブラリとバイナリをリンク)

3)キーチェーンを使用する.hおよび.mファイルにセキュリティライブラリ(#import)およびKeychainItemWrapper(#import "KeychainItemWrapper.h")を追加します。

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;

楽しい!


11

キーチェーンラッパーを使用してパスワードを取得する際に問題が発生した場合は、次のコードを使用します。

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

3

このサンプルコードをチェックアウトする 最初にサンプルコードからアップルのラッパーを試しましたが、これは私にとってははるかに簡単です


2

これを試してください:

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

それが役立つかもしれません。


2

KeychainItemWrapper(ARCバージョン)の使用を検討しましたが、そのObjective Cラッパーが希望どおりに健全であることがわかりませんでした。

私は岸川克己氏によるこのソリューションを使用しました。つまり、コードを少なくして、NSString値を格納するためにキャストを使用する必要がありませんでした。

保存の2つの例:

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

取得の2つの例

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

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

2

上記のコードには小さなバグがあります(ちなみにデイブはあなたの投稿にとても役に立ちました)

資格情報を保存する部分では、適切に機能するために次のコードも必要です。

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

ほとんどの場合、2回目に同じ資格情報で(再)サインインしようとすると、キーチェーンアイテムに既に割り当てられていることがわかり、アプリがクラッシュします。上記のコードでそれは魅力のように動作します。


2

この質問を更新するには:

Swiftチェックアウトを使用している場合は、アクセスグループをサポートするMihai Costeaによるこのドラッグアンドドロップの迅速な実装:

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

キーチェーンを使用する前に:パスワードを保存する前に2回検討してください。多くの場合、認証トークン(永続化セッションIDなど)と電子メールまたはアカウント名を保存するだけで十分です。認証トークンを簡単に無効にして不正なアクセスをブロックし、侵害されたデバイスに再度ログインするようユーザーに要求するが、パスワードのリセットを要求せず、すべてのデバイスに再度ログインする必要がある(私たちはAppleを使用しているだけではありませんか?)


1

ただし、キーチェーンラッパーの代わりにNURLCredentialを使用できるようになりました。それは私たちがする必要があることを行います。



0

以下はうまく機能するはずです:

KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
[keychainItem setObject:@"password you are saving" forKey:kSecValueData]; 
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.