iOS: come archiviare nome utente / password all'interno di un'app?


276

Ho una schermata di accesso nella mia app iOS. Il nome utente e la password verranno salvati in NSUserDefaultse caricati nuovamente nella schermata di accesso quando si accede nuovamente all'app (ovviamente, NSUserDefaultssono permanenti).

Ora, l'utente ha la possibilità di disabilitare la funzione di salvataggio nome utente / password.

Quindi NSUserDefaultssarà cancellato allora.

Ma nella mia app ho bisogno di questo nome utente / password per le query del database per l'utente. Quindi: dove archiviare i dati tranne NSUserDefaults? (Questo luogo può / dovrebbe essere eliminato quando l'utente esce dall'app o si disconnette).


L'utente può cancellarlo solo ripristinando il dispositivo o rimuovendo l'app. Mi sto perdendo qualcosa?

3
E a proposito, se i dati devono essere eliminati quando l'utente esce dall'app, perché non tenerli nella RAM?

10
Dovresti prendere seriamente in considerazione l'utilizzo del Keychain per la memorizzazione di nomi utente e password anziché NSUserDefaults.
Filip Radelic,

1
È possibile ottenere idea di base sull'attuazione swift3 da qui
Anish Parajuli 웃

Dovrei usare sempre kSecValueData e kSecValueData come chiavi? O posso usare qualsiasi stringa come chiave?
Ne AS

Risposte:


424

Dovresti sempre usare Keychain per archiviare nomi utente e password e poiché è archiviato in modo sicuro e accessibile solo per la tua app, non è necessario eliminarlo quando l'app si chiude (se questo era il tuo problema).

Apple fornisce un codice di esempio che archivia, legge ed elimina gli elementi del portachiavi e qui è come utilizzare la classe wrapper portachiavi da quell'esempio che semplifica notevolmente l'utilizzo del Keychain.

Includi Security.framework (in Xcode 3 fai clic con il pulsante destro del mouse sulla cartella frameworks e aggiungi framework esistente. In Xcode 4 seleziona il tuo progetto, quindi seleziona target, vai alla scheda Build Phases e fai clic su + sotto Link Binary With Files) e KeychainItemWrapper .h &. m file nel tuo progetto, #importa il file .h ovunque sia necessario utilizzare il portachiavi e quindi creare un'istanza di questa classe:

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

( YourAppLogin può essere qualsiasi cosa tu abbia scelto di chiamare il tuo articolo Portachiavi e puoi avere più elementi se necessario)

Quindi è possibile impostare il nome utente e la password utilizzando:

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

Falli usare:

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

Oppure cancellali usando:

[keychainItem resetKeychainItem];

5
Ho aggiornato la mia risposta con il codice e la descrizione. Non è così difficile come pensavi.
Filip Radelic,

44
Attantion! Per favore, aggiungi alla tua risposta che solo "copia KeychainItemWrapper" non è abbastanza! Ho avuto il problema, che non posso costruirlo in seguito! Devi aggiungere security.framework al tuo progetto per far funzionare KeychainItemWrapper! (HowTo: Select Project -> Select Target -> Select Tab "Build Phases" -> Select "Link Binary With Libaries" -> "+" -> aggiungi Security.Framework)
Kovu

63
Quando usi ARC, il compilatore ti urlerà per aver usato le costanti kSecValueDatae kSecAttrAccountnel codice Objective-C, quindi assicurati di lanciarle usando (__bridge id), ad esempio, [keychainItem setObject:obj forKey:(__bridge id)kSecValueData];
Joe Hankin,

7
KeychainItemWrapper.m sembra avere una perdita di memoria alla riga 196. Modifica della riga in "self.keychainItemData = [[[NSMutableDictionary alloc] init] autorelease];" lo risolve.
Olof,

12
Quando si utilizza ARC, il codice aggiornato è stato fornito qui da Apple. Guarda il Listato 2-1. Sebbene l'approccio sia lo stesso.
Rick,


48

Una soluzione molto semplice tramite portachiavi .

È un semplice wrapper per il portachiavi di sistema. Basta aggiungere i SSKeychain.h, SSKeychain.m, SSKeychainQuery.he le SSKeychainQuery.mfile al progetto e aggiungere il Security.framework al vostro obiettivo.

Per salvare una password:

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

Per recuperare una password:

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

Dove si setPasswordtrova il valore che si desidera salvare ed forServiceè la variabile in cui si desidera salvarlo e l'account è per quale utente / oggetto è la password e qualsiasi altra informazione.


Sai come usare sskeychain per sincronizzare le app con lo stesso nome utente e password?
Joe Shamuraq,

4
come si memorizza anche un nome utente oltre a una password? Come si elimina un intero account da SSKeychain? Entrambi non sono menzionati nei documenti
user798719

2
Per ottenere il nome utente do NSString *username = [[SSKeychain accountsForService:@"AnyService"][0] valueForKey:@"acct"]. Questo dovrebbe funzionare bene se usi solo un account. Come sempre, assicurati di controllare la lunghezza dell'array prima di provare ad accedere all'indice 0.
Jared Price

27

Puoi semplicemente usare NSURLCredential, salverà sia il nome utente che la password nel portachiavi in ​​sole due righe di codice .

Vedi la mia risposta dettagliata .


13

Ho deciso di rispondere a come utilizzare il portachiavi in ​​iOS 8 utilizzando Obj-C e ARC.

1) Ho usato KeychainItemWrapper (versione ARCifief) di GIST: https://gist.github.com/dhoerl/1170641/download - Aggiungi (+ copia) KeychainItemWrapper.h e .m al tuo progetto

2) Aggiungi il framework di sicurezza al tuo progetto (controlla il progetto> Fasi di costruzione> Collega binario con Librerie)

3) Aggiungi la libreria di sicurezza (#import) e KeychainItemWrapper (#import "KeychainItemWrapper.h") al file .h e .m dove vuoi usare il portachiavi.

4) Per salvare i dati sul portachiavi:

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) Leggi i dati (probabilmente schermata di accesso al caricamento> 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;

Godere!


11

Se riscontri un problema nel recupero della password utilizzando il wrapper portachiavi, utilizza questo codice:

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

3

controlla questo codice di esempio ho provato prima il wrapper di apple dal codice di esempio, ma questo è molto più semplice per me


2

prova questo:

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

possa aiutare.


2

Ho esaminato l'utilizzo di KeychainItemWrapper (la versione ARC) ma non ho trovato il suo wrapper Objective C sano come desiderato.

Ho usato questa soluzione di Kishikawa Katsumi , il che significa che ho scritto meno codice e non ho dovuto usare i cast per memorizzare i valori NSString.

Due esempi di memorizzazione:

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

Due esempi di recupero

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

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

2

C'è un piccolo bug nel codice sopra (a proposito Dave è stato molto utile il tuo post grazie)

Nella parte in cui salviamo le credenziali è necessario anche il seguente codice per funzionare correttamente.

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

molto probabilmente perché la seconda volta che proviamo a (ri) accedere con le stesse credenziali, li trova già assegnati negli elementi del portachiavi e l'app si arresta in modo anomalo. con il codice sopra funziona come un fascino.


2

Per aggiornare questa domanda:

Per coloro che utilizzano il checkout Swift, trascina e rilascia l'implementazione rapida di Mihai Costea che supporta i gruppi di accesso:

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

Prima di utilizzare il portachiavi: considerare due volte prima di memorizzare le password. In molti casi, l'archiviazione di un token di autenticazione (come un ID sessione di persistenza) e l'e-mail o il nome dell'account potrebbero essere sufficienti. Puoi facilmente invalidare i token di autenticazione per bloccare l'accesso non autorizzato, richiedendo all'utente di accedere nuovamente al dispositivo compromesso ma non richiedere la reimpostazione della password e dover accedere nuovamente su tutti i dispositivi (non stiamo solo utilizzando Apple, vero?).


1

Ma ora puoi scegliere NURLCredential anziché il wrapper portachiavi. Fa quello che dobbiamo fare.



0

Quanto segue dovrebbe funzionare bene:

KeychainItemWrapper *keychainItem = [[KeychainItemWrapper alloc] initWithIdentifier:@"YourAppLogin" accessGroup:nil];
[keychainItem setObject:@"password you are saving" forKey:kSecValueData]; 
[keychainItem setObject:@"username you are saving" forKey:kSecAttrAccount];
Utilizzando il nostro sito, riconosci di aver letto e compreso le nostre Informativa sui cookie e Informativa sulla privacy.
Licensed under cc by-sa 3.0 with attribution required.