Actualmente estoy almacenando el nombre de usuario (correo electrónico) y un hash salado del correo electrónico y la contraseña en el KeyChain de iOS. Estoy usando la versión ARC'ified que se encuentra aquí .
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
[wrapper setObject:APP_NAME forKey:(__bridge id)kSecAttrService];
[wrapper setObject:email forKey:(__bridge id)kSecAttrAccount];
[wrapper setObject:token forKey:(__bridge id)kSecValueData];
Todo esto funciona bien cuando necesito sacar el token para mis llamadas de red mientras la aplicación está activa. Funciona para iniciar sesión desde un inicio limpio, así como para todas las llamadas de red. El problema comienza cuando la aplicación está en segundo plano.
Tenga en cuenta que esto solo sucede esporádicamente y todavía tengo que precisarlo para una versión o dispositivo iOS específico.
El usuario dispara una ubicación (monitoreo de región) y quiero actualizar el servidor con su estado. Intento sacar el token del llavero, de la misma manera que lo hago con todas las demás llamadas de red, y actualizo el estado. Pero para algunos usuarios, el valor es nulo. Sin él, no puedo actualizar las cosas de la red. ¿Por qué funcionaría esto para la mayoría, pero no para un pequeño porcentaje?
KeychainItemWrapper *wrapper = [[KeychainItemWrapper alloc] initWithIdentifier:@"MyCustomIdentifier" accessGroup:nil];
NSString *token = [wrapper objectForKey:(__bridge id)kSecValueData];
Volví a la versión no ARC del keychainwrapper, pero sigo obteniendo los mismos resultados. Agradecería cualquier comentario sobre esto. Es solo una pequeña parte de mis usuarios, pero es un problema que me gustaría solucionar y no preocuparme. Gracias por adelantado.
Además, todo mi trabajo en segundo plano está configurado en backgroundTask para evitar que se agote el tiempo de espera. No tengo ningún problema con el trabajo que rodea al llavero, pero no dejo que las cosas sigan adelante hasta que mi token esté lleno.
EDITAR He descubierto mi problema con el llavero que no recupera valores del fondo. Publicaré la respuesta a continuación y la aceptaré, ya que creo que esta pregunta puede resultar valiosa para otros más adelante.
fuente
…AccessibleAlways
si es posible, o almacene un token que solo brinde privilegios limitados (por ejemplo, un token que le permita leer nuevos elementos de noticias, pero no publicar). Al hacerlo, renuncia explícitamente a un nivel de cifrado. Si su aplicación puede esperar hasta el primer desbloqueo, quizás sea mejor usar…AfterFirstUnlock
y dirigir a sus usuarios a desbloquear sus dispositivos primero.Utilizar en
kSecAttrAccessibleAfterFirstUnlock
lugar dekSecAttrAccessibleAlways
.De la documentación de Apple :
fuente
kSecAttrAccessibleAlways
ya está en desusoEn mi caso, watchOS2 accede a los datos del llavero en el lado de iOS.
Al principio, se utiliza kSecAttrAccessibleWhenUnlockedThisDeviceOnly. Puedo leer los datos sin importar si el iPhone está bloqueado o no. Es muy confuso para mí que recibiré un error cuando el reloj intente acceder al llavero:: SecTrustEvaluate [hoja IssuerCommonName SubjectCommonName]
Y en algún caso se convertirá en:: SecOSStatusWith error: [- 25308] Error Domain = NSOSStatusErrorDomain Code = -25308 "ks_crypt: e00002e2 falló en el elemento 'oe' (clase 6, bolsa: 0) Se intentó acceder al elemento mientras el llavero está bloqueado. " UserInfo = {NSDescription = ks_crypt: e00002e2 no pudo 'oe' elemento (clase 6, bolsa: 0) Se intentó acceder al elemento mientras el llavero estaba bloqueado.}
Actualizaré mi respuesta si obtengo más información.
fuente
Esto podría suceder debido a la política de protección de datos de Apples, que en algún nivel es oscura desde la perspectiva de los desarrolladores. La solución es cuando se inicia la aplicación, verifique si el llavero es accesible o no, si no está accesible, puede eliminar su aplicación (con la ventana emergente adecuada) según los tipos de aplicación.
+(BOOL) isKeychainAccessible { NSString *keychainTestKey = @"keychainTestKey"; NSString *keychainTestValue = @"keychainTestValue"; [self createKeychainValue:keychainTestValue forIdentifier:keychainTestKey]; NSString *loadedValue = [self keychainStringFromMatchingIdentifier:keychainTestKey]; [self deleteItemFromKeychainWithIdentifier:keychainTestKey]; return ([keychainTestValue isEqualToString: loadedValue]); }
fuente