iOS KeyChain Items 未在应用的多个目标之间更新
iOS KeyChain Items not being updated between multiple targets of an app
我正在构建一个应用程序,人们需要能够从 iOS 照片应用程序中分享照片。为此,人们需要登录应用程序。
所以我为共享创建了一个新的 iOS 目标。
现在我正在使用 KeychainItemWrapper 来存储用户凭据。
因此,主要目标和 share-sheet 目标都使用 iOS 钥匙串来检索登录信息。
现在当我从主应用程序注销,然后以不同的用户身份登录,然后我开始共享 sheet,看起来共享 sheet 仍然有旧的来自前一个用户的数据。
这怎么可能?我怎样才能确保两个目标始终使用钥匙串中最新最好的数据?
#import "KeychainManager.h"
#import "KeychainItemWrapper.h"
NSString * const CREDENTIALS_IDENTIFIER = @"credentials";
NSString * const COOKIES_IDENTIFIER = @"cookies";
static KeychainManager *keychainManager;
@implementation KeychainManager
+ (instancetype)sharedCredentailsManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
keychainManager = [[KeychainManager alloc] init];
});
return keychainManager;
}
#pragma mark - Getter
- (KeychainItemWrapper *)credentialsKeychainItem {
return [[KeychainItemWrapper alloc] initWithIdentifier:CREDENTIALS_IDENTIFIER accessGroup:nil];
}
- (KeychainItemWrapper *)cookiesKeychainItem {
return [[KeychainItemWrapper alloc] initWithIdentifier:COOKIES_IDENTIFIER accessGroup:nil];
}
- (NSString *)domainName {
NSString *domainName = [self.credentialsKeychainItem objectForKey:(__bridge id)(kSecAttrService)];
return (domainName.length > 0) ? domainName : @"";
}
- (NSString *)userName {
NSString *userName = [self.credentialsKeychainItem objectForKey:(__bridge id)(kSecAttrAccount)];
return (userName.length > 0) ? userName : @"";
}
- (NSString *)password {
NSData *password = [self.credentialsKeychainItem objectForKey:(__bridge id)(kSecValueData)];
if ([password isKindOfClass:[NSString class]] && password.length > 0) {
return (NSString *)password;
} else if ([password isKindOfClass:[NSData class]] && password.length > 0) {
NSString *passwordString = [[NSString alloc] initWithData:password encoding:NSUTF8StringEncoding];
return (passwordString.length > 0) ? password : @"";
} else {
return @"";
}
}
- (NSArray *)cookies {
NSLog(@"Getting cookies");
NSData *cookieData = [self.cookiesKeychainItem objectForKey:(__bridge id)(kSecAttrAccount)];
if ([cookieData isKindOfClass:[NSData class]] && cookieData.length > 0) {
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:cookieData];
NSLog(@"%lu cookies in keychain", (unsigned long)array.count);
return array;
} else {
NSLog(@"No cookies found in KeyChain");
return nil;
}
}
#pragma mark - Setter
- (void)setDomainName:(NSString *)domainName {
[self.credentialsKeychainItem setObject:domainName forKey:(__bridge id)(kSecAttrService)];
}
- (void)setUserName:(NSString *)userName {
[self.credentialsKeychainItem setObject:userName forKey:(__bridge id)(kSecAttrAccount)];
}
- (void)setPassword:(NSString *)password {
[self.credentialsKeychainItem setObject:password forKey:(__bridge id)(kSecValueData)];
}
- (void)setCookies:(NSArray *)cookies {
NSMutableArray *mutableCookies = [[NSMutableArray alloc] init];
for (NSHTTPCookie *cookie in cookies) {
NSLog(@"storing cookie: %@", cookie);
NSDictionary *cookieProperties = cookie.properties;
[mutableCookies addObject:cookieProperties];
}
NSArray *unmutableCookies = [mutableCookies copy];
NSData * encodedData = [NSKeyedArchiver archivedDataWithRootObject:unmutableCookies];
[self.cookiesKeychainItem setObject:encodedData forKey:(__bridge id)(kSecAttrAccount)];
}
# pragma mark - Clear data
- (void)clearAll {
[self clearCredentials];
[self clearCookies];
}
- (void)clearCredentials {
[self.credentialsKeychainItem resetKeychainItem];
}
- (void)clearCookies {
[self.cookiesKeychainItem resetKeychainItem];
}
@end
因此症状是获取用户名、密码、域或 cookie 的函数在同一应用程序的不同目标之间都会给出不同的结果。
我发现了问题。我必须在两个目标的权利中设置钥匙串共享。
有关如何设置的指南可在此处找到:
http://evgenii.com/blog/sharing-keychain-in-ios/
然后您必须将钥匙串项目存储在访问组中。当我尝试这样做时,当我想在钥匙串中存储一些东西时,KeychainItemWrapper 给出了一些断言失败,然后我可以使用以下 link 解决这个问题:
KeychainItemWrapper error when specifying an access group
我正在构建一个应用程序,人们需要能够从 iOS 照片应用程序中分享照片。为此,人们需要登录应用程序。
所以我为共享创建了一个新的 iOS 目标。 现在我正在使用 KeychainItemWrapper 来存储用户凭据。 因此,主要目标和 share-sheet 目标都使用 iOS 钥匙串来检索登录信息。
现在当我从主应用程序注销,然后以不同的用户身份登录,然后我开始共享 sheet,看起来共享 sheet 仍然有旧的来自前一个用户的数据。
这怎么可能?我怎样才能确保两个目标始终使用钥匙串中最新最好的数据?
#import "KeychainManager.h"
#import "KeychainItemWrapper.h"
NSString * const CREDENTIALS_IDENTIFIER = @"credentials";
NSString * const COOKIES_IDENTIFIER = @"cookies";
static KeychainManager *keychainManager;
@implementation KeychainManager
+ (instancetype)sharedCredentailsManager {
static dispatch_once_t onceToken;
dispatch_once(&onceToken, ^{
keychainManager = [[KeychainManager alloc] init];
});
return keychainManager;
}
#pragma mark - Getter
- (KeychainItemWrapper *)credentialsKeychainItem {
return [[KeychainItemWrapper alloc] initWithIdentifier:CREDENTIALS_IDENTIFIER accessGroup:nil];
}
- (KeychainItemWrapper *)cookiesKeychainItem {
return [[KeychainItemWrapper alloc] initWithIdentifier:COOKIES_IDENTIFIER accessGroup:nil];
}
- (NSString *)domainName {
NSString *domainName = [self.credentialsKeychainItem objectForKey:(__bridge id)(kSecAttrService)];
return (domainName.length > 0) ? domainName : @"";
}
- (NSString *)userName {
NSString *userName = [self.credentialsKeychainItem objectForKey:(__bridge id)(kSecAttrAccount)];
return (userName.length > 0) ? userName : @"";
}
- (NSString *)password {
NSData *password = [self.credentialsKeychainItem objectForKey:(__bridge id)(kSecValueData)];
if ([password isKindOfClass:[NSString class]] && password.length > 0) {
return (NSString *)password;
} else if ([password isKindOfClass:[NSData class]] && password.length > 0) {
NSString *passwordString = [[NSString alloc] initWithData:password encoding:NSUTF8StringEncoding];
return (passwordString.length > 0) ? password : @"";
} else {
return @"";
}
}
- (NSArray *)cookies {
NSLog(@"Getting cookies");
NSData *cookieData = [self.cookiesKeychainItem objectForKey:(__bridge id)(kSecAttrAccount)];
if ([cookieData isKindOfClass:[NSData class]] && cookieData.length > 0) {
NSArray *array = [NSKeyedUnarchiver unarchiveObjectWithData:cookieData];
NSLog(@"%lu cookies in keychain", (unsigned long)array.count);
return array;
} else {
NSLog(@"No cookies found in KeyChain");
return nil;
}
}
#pragma mark - Setter
- (void)setDomainName:(NSString *)domainName {
[self.credentialsKeychainItem setObject:domainName forKey:(__bridge id)(kSecAttrService)];
}
- (void)setUserName:(NSString *)userName {
[self.credentialsKeychainItem setObject:userName forKey:(__bridge id)(kSecAttrAccount)];
}
- (void)setPassword:(NSString *)password {
[self.credentialsKeychainItem setObject:password forKey:(__bridge id)(kSecValueData)];
}
- (void)setCookies:(NSArray *)cookies {
NSMutableArray *mutableCookies = [[NSMutableArray alloc] init];
for (NSHTTPCookie *cookie in cookies) {
NSLog(@"storing cookie: %@", cookie);
NSDictionary *cookieProperties = cookie.properties;
[mutableCookies addObject:cookieProperties];
}
NSArray *unmutableCookies = [mutableCookies copy];
NSData * encodedData = [NSKeyedArchiver archivedDataWithRootObject:unmutableCookies];
[self.cookiesKeychainItem setObject:encodedData forKey:(__bridge id)(kSecAttrAccount)];
}
# pragma mark - Clear data
- (void)clearAll {
[self clearCredentials];
[self clearCookies];
}
- (void)clearCredentials {
[self.credentialsKeychainItem resetKeychainItem];
}
- (void)clearCookies {
[self.cookiesKeychainItem resetKeychainItem];
}
@end
因此症状是获取用户名、密码、域或 cookie 的函数在同一应用程序的不同目标之间都会给出不同的结果。
我发现了问题。我必须在两个目标的权利中设置钥匙串共享。
有关如何设置的指南可在此处找到:
http://evgenii.com/blog/sharing-keychain-in-ios/
然后您必须将钥匙串项目存储在访问组中。当我尝试这样做时,当我想在钥匙串中存储一些东西时,KeychainItemWrapper 给出了一些断言失败,然后我可以使用以下 link 解决这个问题: KeychainItemWrapper error when specifying an access group