Я создаю приложение для iOS для своего веб-сайта и пытаюсь использовать OAuth2 для управления учетными данными для входа.При входе пользователя в систему я успешно подключаюсь к своей конечной точке аутентификации, используя предоставленные имя пользователя и пароль, и пытаюсь сохранить токен доступа и токен обновления в цепочке для ключей, поэтому пользователю не нужно предоставлять учетные данные для продвижения вперед.
У меня проблемы с хранением токена обновления и токена доступа в моей цепочке для ключей, следуя инструкциям из этих источников:
Я могу успешно сохранить либоТокен доступа или токен обновления, но независимо от того, какой из них я храню первым, при попытке сохранить другой я получаю следующее сообщение об ошибке: «Указанный элемент уже существует в цепочке для ключей.»
Я добавилCheckForExisting
функция для удаления любых существующих элементов с такими же характеристиками, но когда я пытаюсь удалить существующий элемент цепочки для ключей, используя same query
, я получаю статус errSecItemNotFound
.Так что, к сожалению, мне говорят, что я не могу создать свой элемент, потому что он уже существует, но я не могу удалить существующий элемент, потому что не существует никакого существующего элемента.
Моя гипотеза состоит в том, что созданиеэлемента маркера доступа блокирует создание элемента маркера обновления, поэтому я надеюсь, что кто-то может пролить свет на следующее:
- Почему блокируется создание второго элемента?Есть ли в цепочке для ключей какие-то встроенные проверки первичных ключей, которые я нажимаю (например, не может хранить более одного
kSecClassInternetPassword
)? - Как правильно различать два токена.Прямо сейчас я использую
kSecAttrLabel
, но это выстрел в темноте.
Обратите внимание, что я надеюсь объяснить , почему мой текущий подход терпит неудачу,Я абсолютно приветствую альтернативные реализации, но я действительно хочу понять, что здесь происходит за кулисами, поэтому, если это возможно, пожалуйста, включите объяснение того, где альтернативная реализация избегает ловушек, на которые я, похоже, попал.* Код Swift4 для хранения токенов:
func StoreTokens(username: String, access_token: String, refresh_token: String) throws {
func CheckForExisting(query: [String: Any]) throws {
let status = SecItemDelete(query as CFDictionary)
guard status == errSecSuccess || status == errSecItemNotFound else {
let error_message = SecCopyErrorMessageString(status, nil)!
throw KeychainError.unhandledError(status: error_message)
}
}
let configuration = ConfigurationDetails()
let server = configuration.server
let access_token = access_token.data(using: String.Encoding.utf8)!
let refresh_token = refresh_token.data(using: String.Encoding.utf8)!
let access_token_query: [String: Any] = [
kSecClass as String: kSecClassInternetPassword,
kSecAttrAccount as String: username,
kSecAttrServer as String: server,
kSecAttrLabel as String: "AccessToken",
kSecValueData as String: access_token
]
let refresh_token_query: [String: Any] = [
kSecClass as String: kSecClassInternetPassword,
kSecAttrAccount as String: username,
kSecAttrServer as String: server,
kSecAttrLabel as String: "RefreshToken",
kSecValueData as String: refresh_token
]
try CheckForExisting(query: access_token_query)
let access_status = SecItemAdd(access_token_query as CFDictionary, nil)
guard access_status == errSecSuccess else {
let error_message = SecCopyErrorMessageString(access_status, nil)!
throw KeychainError.unhandledError(status: error_message)
}
try CheckForExisting(query: refresh_token_query)
let refresh_status = SecItemAdd(refresh_token_query as CFDictionary, nil)
guard refresh_status == errSecSuccess else {
let error_message = SecCopyErrorMessageString(refresh_status, nil)!
throw KeychainError.unhandledError(status: error_message)
}
}