UICKeyChainStore 2.2.1

UICKeyChainStore 2.2.1

测试已测试
Lang语言 Obj-CObjective C
许可证 MIT
发布上次发布2020 年 9 月

kishikawa katsumi 维护。



UICKeyChainStore

CI Status Coverage Status Carthage compatible Version License Platform

UICKeyChainStore 是一个简单的 Keychain 包装器,适用于 iOS 和 OS X。让使用 Keychain API 与使用 NSUserDefaults 一样简单。

寻找用 Swift 编写的库?

试试 KeychainAccess
KeychainAccess 是 UICKeyChainStore 的下一代。

从 1.x 迁移到 2.0

synchronize 方法已弃用。调用此方法不再需要(将忽略)。

功能

使用说明

基础知识

保存应用密码

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];
keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef";

保存互联网密码

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"]
                                                          protocolType:UICKeyChainStoreProtocolTypeHTTPS];
keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef";

实例化

为应用密码创建密钥链

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];
UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"kishikawakatsumi.git"
                                                            accessGroup:@"12ABCD3E4F.shared"];

为互联网密码创建密钥链

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"]
                                                          protocolType:UICKeyChainStoreProtocolTypeHTTPS];
UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"]
                                                          protocolType:UICKeyChainStoreProtocolTypeHTTPS
                                                    authenticationType:UICKeyChainStoreAuthenticationTypeHTMLForm];

添加一项

下标

keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef"

设置方法

[keychain setString:@"01234567-89ab-cdef-0123-456789abcdef" forKey:@"kishikawakatsumi"];

错误处理

if (![keychain setString:@"01234567-89ab-cdef-0123-456789abcdef" forKey:@"kishikawakatsumi"]) {
    // error has occurred
}
NSError *error;
[keychain setString:@"01234567-89ab-cdef-0123-456789abcdef" forKey:@"kishikawakatsumi" error:&error];
if (error) {
    NSLog(@"%@", error.localizedDescription);
}

获取一项

下标(自动转换为字符串)

NSString *token = keychain[@"kishikawakatsumi"]

获取方法

转换为字符串
NSString *token = [keychain stringForKey:@"kishikawakatsumi"];
转换为NSData
NSData *data = [keychain dataForKey:@"kishikawakatsumi"];

错误处理

首先获取可能失败(值或错误)对象

NSError *error;
NSString *token = [keychain stringForKey:@"" error:&error];
if (error) {
    NSLog(@"%@", error.localizedDescription);
}

移除项

下标访问

keychain[@"kishikawakatsumi"] = nil

remove方法

[keychain removeItemForKey:@"kishikawakatsumi"];

错误处理

if (![keychain removeItemForKey:@"kishikawakatsumi"]) {
    // error has occurred
}
NSError *error;
[keychain removeItemForKey:@"kishikawakatsumi" error:&error];
if (error) {
    NSLog(@"%@", error.localizedDescription);
}

标签和注释

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"]
                                                          protocolType:UICKeyChainStoreProtocolTypeHTTPS];
[keychain setString:@"01234567-89ab-cdef-0123-456789abcdef"
             forKey:@"kishikawakatsumi"
              label:@"github.com (kishikawakatsumi)"
            comment:@"github access token"];

配置(可访问性、共享、iCould 同步)

可访问性

默认可访问性与后台应用匹配(=kSecAttrAccessibleAfterFirstUnlock)
UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];
针对后台应用
创建实例
UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];
keychain.accessibility = UICKeyChainStoreAccessibilityAfterFirstUnlock;

keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef"
针对前台应用程序
创建实例
UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];
keychain.accessibility = UICKeyChainStoreAccessibilityWhenUnlocked;

keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef"

共享密钥链项

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"kishikawakatsumi.git"
                                                            accessGroup:@"12ABCD3E4F.shared"];

与iCloud同步密钥链项

创建实例
UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];
keychain.synchronizable = YES;

keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef"

Touch ID集成

任何需要认证的操作必须在后台线程中运行。
如果您在主线程中运行,UI线程将锁定,以便系统尝试显示认证对话框。

添加一个Touch ID受保护的项目

如果您想存储受Touch ID保护的密钥链项目,请指定accessibilityauthenticationPolicy属性。

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    [keychain setAccessibility:UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly
          authenticationPolicy:UICKeyChainStoreAuthenticationPolicyUserPresence];

    keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef"
});

更新一个Touch ID受保护的项目

与添加时相同的方式。

如果有可能尝试添加的项目已经存在并且受到保护,请不要在主线程上运行。 因为更新受保护的项目需要身份验证。

另外,在更新时,如果想要显示自定义的身份验证提示消息,请指定一个authenticationPrompt属性。如果项目未被保护,则忽略authenticationPrompt参数。

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    [keychain setAccessibility:UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly
          authenticationPolicy:UICKeyChainStoreAuthenticationPolicyUserPresence];
    keychain.authenticationPrompt = @"Authenticate to update your access token";

    keychain[@"kishikawakatsumi"] = @"01234567-89ab-cdef-0123-456789abcdef"
});

获取一个Touch ID受保护的项目

与获取普通项目的方式相同。如果尝试获取的项目受到保护,将会自动显示Touch ID或密码验证。
如果您想要显示自定义的身份验证提示消息,请指定一个authenticationPrompt属性。如果项目未被保护,则忽略authenticationPrompt参数。

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];

dispatch_async(dispatch_get_global_queue(DISPATCH_QUEUE_PRIORITY_BACKGROUND, 0), ^{
    [keychain setAccessibility:UICKeyChainStoreAccessibilityWhenPasscodeSetThisDeviceOnly
          authenticationPolicy:UICKeyChainStoreAuthenticationPolicyUserPresence];
    keychain.authenticationPrompt = @"Authenticate to update your access token";

    NSString *token = keychain[@"kishikawakatsumi"];
});

移除一个Touch ID受保护的项目

与移除普通项目的方式相同。在移除密钥链项目时没有显示Touch ID或密码验证的方式。

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithService:@"com.example.github-token"];

keychain[@"kishikawakatsumi"] = nil;

共享Web凭据

共享网页凭据是一种编程接口,允许原生iOS应用程序与其网站对应版本共享凭据。例如,用户可以在Safari中登录网站,输入用户名和密码,并使用iCloud密钥链保存这些凭据。稍后,用户可以从同一开发者处运行原生应用程序,而且不需要用户重新输入用户名和密码,共享网页凭据使其能够访问之前在Safari中输入的凭据。用户还可以在应用程序内部创建新账户、更新密码或从应用程序中删除其账户。这些更改将由Safari保存并使用。
https://developer.apple.com/library/ios/documentation/Security/Reference/SharedWebCredentialsRef/

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://kishikawakatsumi.com"]
protocolType:UICKeyChainStoreProtocolTypeHTTPS];
NSString *username = @"[email protected]";
NSString *password = keychain[username];
if (password) {
    // If found password in the Keychain,
    // then log into the server
} else {
    // If not found password in the Keychain,
    // try to read from Shared Web Credentials
    [keychain sharedPasswordForAccount:username completion:^(NSString *password, NSError *error) {
        if (password) {
            // If found password in the Shared Web Credentials,
            // then log into the server
            // and save the password to the Keychain

            keychain[username] = password
        } else {
            // If not found password either in the Keychain also Shared Web Credentials,
            // prompt for username and password

            // Log into server

            // If the login is successful,
            // save the credentials to both the Keychain and the Shared Web Credentials.

            keychain[username] = password
            [keychain setSharedPassword:password forAccount:username completion:nil];
        }
    }];
}

请求所有相关域名凭据

[UICKeyChainStore requestSharedWebCredentialWithCompletion:^(NSArray *credentials, NSError *error) {

}];

生成强随机密码

生成与Safari自动填充使用的相同格式的强随机密码(xxx-xxx-xxx-xxx)。

NSString *password = [UICKeyChainStore generatePassword];
NSLog(@"%@", password); // => Nhu-GKm-s3n-pMx

如何设置共享网页凭据

  1. 将com.apple.developer.associated-domains权限添加到您的应用程序中。此权限必须包含您想要共享凭据的所有域名。
  1. 将apple-app-site-association文件添加到您的网站中。此文件必须包含网站想要共享凭据的'app'的应用标识符,并且必须正确签名。
  1. 当应用程序安装时,系统将为每个相关域名下载和验证网站关联文件。如果验证成功,应用程序将与该域名相关联。

更多详情
https://developer.apple.com/library/ios/documentation/Security/Reference/SharedWebCredentialsRef/

调试

打印密钥链对象时显示所有存储项

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"]
                                                          protocolType:UICKeyChainStoreProtocolTypeHTTPS];
NSLog(@"%@", keychain);
=>
(
{
    accessibility = ak;
    authenticationType = dflt;
    class = InternetPassword;
    key = kishikawakatsumi;
    protocol = htps;
    server = "github.com";
    synchronizable = 0;
    value = "01234567-89ab-cdef-0123-456789abcdef";
}    {
    accessibility = ck;
    authenticationType = dflt;
    class = InternetPassword;
    key = hirohamada;
    protocol = htps;
    server = "github.com";
    synchronizable = 1;
    value = "11111111-89ab-cdef-1111-456789abcdef";
}    {
    accessibility = ak;
    authenticationType = dflt;
    class = InternetPassword;
    key = honeylemon;
    protocol = htps;
    server = "github.com";
    synchronizable = 0;
    value = "22222222-89ab-cdef-2222-456789abcdef";
})

获取所有存储密钥

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"]
                                                          protocolType:UICKeyChainStoreProtocolTypeHTTPS];

NSArray *keys = keychain.allKeys;
for (NSString *key in keys) {
    NSLog(@"key: %@", key);
}
=>
key: kishikawakatsumi
key: hirohamada
key: honeylemon

获取所有存储项

UICKeyChainStore *keychain = [UICKeyChainStore keyChainStoreWithServer:[NSURL URLWithString:@"https://github.com"]
                                                          protocolType:UICKeyChainStoreProtocolTypeHTTPS];

NSArray *items = keychain.allItems;
for (NSString *item in items) {
    NSLog(@"item: %@", item);
}
=>

item: {
    accessibility = ak;
    authenticationType = dflt;
    class = InternetPassword;
    key = kishikawakatsumi;
    protocol = htps;
    server = "github.com";
    synchronizable = 0;
    value = "01234567-89ab-cdef-0123-456789abcdef";
}
item: {
    accessibility = ck;
    authenticationType = dflt;
    class = InternetPassword;
    key = hirohamada;
    protocol = htps;
    server = "github.com";
    synchronizable = 1;
    value = "11111111-89ab-cdef-1111-456789abcdef";
}
item: {
    accessibility = ak;
    authenticationType = dflt;
    class = InternetPassword;
    key = honeylemon;
    protocol = htps;
    server = "github.com";
    synchronizable = 0;
    value = "22222222-89ab-cdef-2222-456789abcdef";
}

方便的类方法

使用默认服务名称(=包标识符)添加项。

[UICKeyChainStore setString:@"01234567-89ab-cdef-0123-456789abcdef" forKey:@"kishikawakatsumi"];

或者指定服务名称。

[UICKeyChainStore setString:@"01234567-89ab-cdef-0123-456789abcdef"
                     forKey:@"kishikawakatsumi"
                    service:@"com.example.github-token"];

删除项。

[UICKeyChainStore removeItemForKey:@"kishikawakatsumi" service:@"com.example.github-token"];

要设置nil值也适用于通过密钥删除项。

[UICKeyChainStore setString:nil forKey:@"kishikawakatsumi" service:@"com.example.github-token"];

要求

iOS 4.3 或更高版本 OS X 10.7 或更高版本

安装

Swift 包管理器

// swift-tools-version:5.0
import PackageDescription

let package = Package(
    name: "MyLibrary",
    products: [
        .library(name: "MyLibrary", targets: ["MyLibrary"]),
    ],
    dependencies: [
        .package(url: "https://github.com/kishikawakatsumi/UICKeyChainStore.git", from: "2.1.2"),
    ],
    targets: [
        .target(name: "MyLibrary", dependencies: ["UICKeyChainStore"]),
    ]
)

$ swift build

use_frameworks!

target 'EampleApp' do
  pod 'UICKeyChainStore'
end

target 'EampleApp WatchKit Extension' do
  platform :watchos, '2.0'
  pod 'UICKeyChainStore'
end

手动添加到您的项目

  1. Security.framework添加到您的目标中。
  2. 将Lib中的文件(UICKeyChainStore.hUICKeyChainStore.m)复制到您的项目中。

作者

kishikawa katsumi, [email protected]

许可协议

UICKeyChainStore遵循MIT许可协议。有关更多信息,请参阅LICENSE文件。