UICKeyChainStore
UICKeyChainStore 是一个简单的 Keychain 包装器,适用于 iOS 和 OS X。让使用 Keychain API 与使用 NSUserDefaults 一样简单。
寻找用 Swift 编写的库?
试试 KeychainAccess。
KeychainAccess 是 UICKeyChainStore 的下一代。
从 1.x 迁移到 2.0
synchronize
方法已弃用。调用此方法不再需要(将忽略)。
功能
- 简单的接口
- 支持访问组
- 支持可访问性
- 支持iCloud分享
- 支持TouchID和Keychain集成(iOS 8+)
- 支持共享Web凭据(iOS 8+)
- 在iOS和OS X上均适用
- 支持watchOS 2
使用说明
基础知识
保存应用密码
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保护的密钥链项目,请指定accessibility
和authenticationPolicy
属性。
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
如何设置共享网页凭据
- 将com.apple.developer.associated-domains权限添加到您的应用程序中。此权限必须包含您想要共享凭据的所有域名。
- 将apple-app-site-association文件添加到您的网站中。此文件必须包含网站想要共享凭据的'app'的应用标识符,并且必须正确签名。
- 当应用程序安装时,系统将为每个相关域名下载和验证网站关联文件。如果验证成功,应用程序将与该域名相关联。
更多详情
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
手动添加到您的项目
- 将
Security.framework
添加到您的目标中。 - 将Lib中的文件(
UICKeyChainStore.h
和UICKeyChainStore.m
)复制到您的项目中。
作者
kishikawa katsumi, [email protected]
许可协议
UICKeyChainStore遵循MIT许可协议。有关更多信息,请参阅LICENSE文件。