Я использую keychain ios (keychainItemWrapper
/SSKeychain
), чтобы сохранить токен входа в приложение и поддерживать состояние входа. В настоящее время я храню простой NSDictionary
в цепочке ключей, содержащей мой токен, истечение срока действия токена и токен обновления. Я сериализую его в NSData и сохраняю, используя kSecValueData
. Я также устанавливаю kSecAttrAccount
и kSecAttrService
, но не использую их для auth.ios хранить лог входа в KeyChain не удается получить, редко и случайным образом, но последовательно
Это отлично работает примерно в 95% случаев. Проблема в том, что это случайным образом, непредсказуемо и спорадически, keychain не возвращает данные, когда я прошу его получить токен. Обычно после умеренного времени от приложения, при повторном открытии. Это не должно быть в фоновом режиме или после какой-либо конкретной задержки.
Неисправность возникает при запросе моего NSData
ниже и возвращает <>
вместо <ABCD EFGH IJKL ....>
. Я думаю, что это нуль. Таким образом, код думает, что пользователь не зашел в систему и сразу же отключил его на моей целевой странице регистрации/входа в приложение, без ошибки выхода из системы, ошибки истечения токена и т. Д. Если я скрою приложение, а затем снова открою его, он почти всегда получит правильный брелок info, и пользователь снова войдет в систему.
Это создает путаницу при столкновении. Это также означает, что пользователь не может поддерживать это истинное 100% регистрируемое состояние, изредка случайно выходить из системы. Я не мог предсказать это или отладить его, и изменение библиотек ключей, как показано ниже, не исправило это для меня. Это случается для меня, и нескольких пользователей TestFlight, и в нашем производственном приложении.
Любые предложения по сохранению целостности связки ключей и загрузке 100% времени? Мы готовы реализовать хранилище резервных копий NSUserDefaults на токене, чтобы использовать в этих случаях, что-то, что я действительно не хочу делать, чтобы хранить токен аутентификации.
Хранение:
// load keychain
KeychainItemWrapper *keychainItem = [KeychainItemWrapper keyChainWrapperForKeyID:kcIdentifier];
NSString *firstLaunch = [keychainItem objectForKey: (__bridge id)(kSecAttrAccount)];
if (firstLaunch == nil){
// initialize if needed
[keychainItem setObject:email forKey: (__bridge id)(kSecAttrAccount)];
[keychainItem setObject:kcIdentifier forKey: (__bridge id)kSecAttrService];
[keychainItem setObject:(id)kSecAttrAccessibleAfterFirstUnlock forKey:(id)kSecAttrAccessible];
}
// serialize "auth" NSDictionary into NSData and store
NSString *error;
NSData *dictionaryData = [NSPropertyListSerialization dataFromPropertyList:auth format:NSPropertyListXMLFormat_v1_0 errorDescription:&error];
[keychainItem setObject:dictionaryData forKey:(id)kSecValueData];
Загрузка:
// after similar KeychainItemWrapper initialization as above
NSData *dictionaryData = [keychainItem objectForKey:(id)kSecValueData];
NSString *error;
NSDictionary *auth = [NSPropertyListSerialization propertyListFromData:dictionaryData mutabilityOption:NSPropertyListImmutable format:nil errorDescription:&error];
NSString *token = auth[@"access_token"];
Я также попытался с помощью библиотеки SSKeychain
CocoaPod, который широко доступен, и обертку вокруг логики брелка. Это более чистый доступ, но с той же проблемой не удается. Здесь я просто храню значения NSString
, так как не было прямого способа хранить NSData
в lib.
// store in keychain
[SSKeychain setAccessibilityType:kSecAttrAccessibleAfterFirstUnlock];
[SSKeychain setPassword:auth[@"access_token"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_TOKEN];
[SSKeychain setPassword:auth[@"expires_at"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_EXPIRES_AT];
[SSKeychain setPassword:auth[@"refresh_token"] forService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_REFRESH_TOKEN];
// load from keychain
[SSKeychain setAccessibilityType:kSecAttrAccessibleAfterFirstUnlock];
NSString *token = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_TOKEN];
NSString *expires_at = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_EXPIRES_AT];
NSString *refresh_token = [SSKeychain passwordForService:SSKEYCHAIN_SERVICE account:SSKEYCHAIN_REFRESH_TOKEN];
Если брелок не работает, вы должны получить код ошибки. Что это? – Segev
У меня такая же проблема, когда поиск случайно прерывается. Вот вспомогательный метод - код ошибки keychain для строки: https://gist.github.com/inorganik/f9971e65f71e037650b39b5f182e157e – inorganik
Я попытаюсь зарегистрировать ошибки. это, вероятно, происходит внутри библиотек, которые я использую, которые не отображают параметр & error. – Miro