向当前包 ID 添加前缀会重置钥匙串?

adding prefix to your current bundle id resets the keychain?

我有一个应用程序 (app1) 在应用程序商店中,捆绑 ID com.x。y 现在我正在使用同一个开发者帐户开发另一个应用程序(app2),包 ID com.x.z

我想让存储在 app1 中的钥匙串值可供 app2 使用。

钥匙串的可用性由钥匙串访问组决定。 因此,如果我将前缀(当前团队 ID)添加到两个包 ID,我就能获得这些值。例如 teamid.com.x.y teamid.com.x.z

问题是 当我将前缀添加到 appstore 中的 app1 时,它会再次要求登录凭据,我不想这样做,因为应用程序有很多用户。 我之前没有使用前缀我只是添加了它们。 有没有一种方法可以让我获得这两个应用程序的钥匙串访问权限,而无需用户再次登录。

首先,重要的是要认识到 Xcode 已经将 AppIdentifierPrefix 添加到您的标识符中。不幸的是,它在 GUI 中隐藏了它,但是如果您打开 entitlements plist,您就会看到它。这是用于对应用程序进行签名的标识符,也是用于实施访问控制的部分。我不相信您添加的 teamid 前缀真的有任何作用。我通常会推荐一个访问组 com.x.sharedcom.x.appgroup.shared 而不是使用 com.x.z (我假设 com.x.y 已经存在,所以你不能改变它)。

我在这里假设您不想强迫用户升级 App1,对吗?我正朝着这个假设前进。

如果你可以升级 App1(不要求升级,但要确​​保所有 客户都有升级版本),那么只存储在 com.x.y 如果它存在。否则,存储在 com.x.shared:

  • 当您从钥匙串读取时,不要使用访问组。这将得到第一个匹配的记录。
  • 写入钥匙串时,使用您读取的记录中的访问组。

如果您现在根本不想升级 App1(无论是否需要),那么总是在 App2 中读取和写入 com.x.y

当您准备好结束 com.x.y 组的生命周期时(如果您最终能够升级所有 App1 支持的用户),那么您可以切换到:

  • 阅读 com.x.y。如果找到,将其删除,然后将其重新创建为 com.x.shared。您可以在应用程序启动时一次性执行此操作(只需写一个 NSUserDefaults 表示您已经完成。
  • 从那时起,请始终明确使用 com.x.shared

这里的关键工具是,当您请求一个明确的访问组时,您必须提供整个内容,包括您的 AppId(它不会显示在 Xcode GUI 中)。您当然可以对其进行硬编码,但更好的解决方案是动态查询它。我使用 David H's code:

的更新版本
- (NSString *)bundleSeedID {
  NSDictionary *query = @{ (__bridge id)kSecClass : (__bridge id)kSecClassGenericPassword,
                           (__bridge id)kSecAttrAccount : @"bundleSeedIDQuery",
                           (__bridge id)kSecAttrService : @"",
                           (__bridge id)kSecReturnAttributes : (id)kCFBooleanTrue
                           };
  CFDictionaryRef result = nil;
  OSStatus status = SecItemCopyMatching((__bridge CFTypeRef)query,
                                        (CFTypeRef *)&result);
  if (status == errSecItemNotFound)
    status = SecItemAdd((__bridge CFTypeRef)query, (CFTypeRef *)&result);
  if (status != errSecSuccess)
    return nil;
  NSString *accessGroup = [(__bridge NSDictionary *)result
                           objectForKey:(__bridge id)kSecAttrAccessGroup];
  NSArray *components = [accessGroup componentsSeparatedByString:@"."];
  NSString *bundleSeedID = components[0];
  CFRelease(result);
  return bundleSeedID;
}

这会在运行时告诉您您的前缀。它这样做是为了创建一个虚假的钥匙串条目,然后查询它并查看附加到它的访问组。

您可能对 Renaissance.io 2014 年 Getting Security and Privacy Right 的第一部分感兴趣。您可以跳至 "Protecting Secrets with Keychain."