Tôi đang sử dụng khóa ios (keychainItemWrapper
/SSKeychain
) để lưu mã thông báo đăng nhập của ứng dụng và duy trì trạng thái đăng nhập. Hiện tại tôi lưu trữ một đơn giản NSDictionary
trong keychain chứa mã thông báo của tôi, hết hạn mã thông báo và mã thông báo làm mới. Tôi sắp xếp nó vào NSData và lưu trữ bằng cách sử dụng kSecValueData
. Tôi cũng đặt kSecAttrAccount
và kSecAttrService
, nhưng không sử dụng những thông tin đó cho auth.ios lưu trữ mã thông báo đăng nhập trong KeyChain không thể truy xuất, hiếm khi và ngẫu nhiên, nhưng nhất quán
Công trình này tuyệt vời, khoảng 95% thời gian. Vấn đề là rằng ngẫu nhiên, không thể đoán trước và rời rạc, keychain không trả lại dữ liệu khi tôi yêu cầu nó để lấy mã thông báo. Nó thường là sau một thời gian vừa phải ra khỏi ứng dụng, khi mở lại nó. Nó không phải là từ nền, hoặc sau bất kỳ sự chậm trễ cụ thể mặc dù.
Không thành công khi yêu cầu NSData
dưới đây và trả lại <>
thay vì <ABCD EFGH IJKL ....>
. Tôi nghĩ là không. Do đó, mã cho rằng người dùng không đăng nhập và bỏ chúng ngay lập tức trên trang đích Đăng nhập/Đăng nhập của ứng dụng của tôi, mà không có lỗi đăng xuất, lỗi hết hạn mã thông báo, v.v. Nếu tôi thu nhỏ ứng dụng, sau đó mở lại, nó hầu như luôn nhận được đúng khóa thông tin và người dùng đã đăng nhập lại.
Điều này tạo ra một trải nghiệm khó hiểu khi gặp phải. Điều này cũng có nghĩa là người dùng không thể duy trì trạng thái đăng nhập 100% thực sự này, đôi khi bị đăng xuất ngẫu nhiên. Tôi đã không thể dự đoán nó hoặc gỡ lỗi nó và thay đổi thư viện keychain, như hình dưới đây, đã không cố định nó cho tôi. Nó xảy ra với tôi, và một số người dùng TestFlight, và trong ứng dụng sản xuất của chúng tôi hiện nay.
Bất kỳ đề xuất nào về cách duy trì tính toàn vẹn của keychain và tải 100% thời gian? Chúng ta đã sẵn sàng để thực hiện một lưu trữ sao lưu NSUserDefaults trên mã thông báo để sử dụng trong những trường hợp này, một cái gì đó tôi thực sự không muốn làm để lưu trữ một mã thông báo auth.
Lưu trữ:
// 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];
Chở Hàng:
// 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"];
Tôi cũng đã cố gắng sử dụng các thư viện SSKeychain
CocoaPod đó là phổ biến rộng rãi, và một bọc xung quanh logic keychain. Nó là một truy cập sạch hơn nhưng không thành công với cùng một vấn đề. Ở đây tôi chỉ lưu trữ các giá trị NSString
vì không có cách nào trực tiếp để lưu trữ NSData
trong 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];
Nếu khóa không thành công, bạn sẽ nhận được mã lỗi. Nó là gì? – Segev
Tôi có cùng một vấn đề, nơi truy xuất ngẫu nhiên không thành công. Dưới đây là phương thức trợ giúp - mã lỗi keychain cho chuỗi: https://gist.github.com/inorganik/f9971e65f71e037650b39b5f182e157e – inorganik
tôi sẽ cố gắng ghi lại lỗi. nó có khả năng xảy ra bên trong các thư viện tôi sử dụng, mà không phơi bày một tham số & lỗi. – Miro