KeychainAccess

KeychainAccess

Swift封装库简化iOS和macOS的Keychain操作

KeychainAccess是一个Swift封装库,简化了iOS和macOS上的Keychain操作。该库支持访问组、可访问性控制、iCloud同步,并提供Touch ID/Face ID集成和共享Web凭证等功能。兼容Swift 3、4和5,KeychainAccess让Swift项目中安全存储和检索敏感数据变得简单高效。

KeychainAccessSwiftiOSmacOS安全存储Github开源项目

KeychainAccess

构建状态 Carthage 兼容 支持 SPM 版本 平台

KeychainAccess 是一个简单的 Swift 封装器,用于在 iOS 和 macOS 上操作 Keychain。它使 Keychain API 的使用变得极其简单,在 Swift 中更加易用。

<img src="https://github.com/kishikawakatsumi/KeychainAccess/assets/40610/4de4aae1-6fc1-4477-af6d-afbe6d164da0" width="320px" /> <img src="https://github.com/kishikawakatsumi/KeychainAccess/assets/40610/2980ea84-862b-4067-b9b7-90de629171b9" width="320px" /> <img src="https://github.com/kishikawakatsumi/KeychainAccess/assets/40610/3299347d-eb1b-446c-921c-778fa493f818" width="320px" />

:bulb: 特性

:book: 使用方法

:eyes: 另请参阅:

:key: 基础用法

保存应用程序密码

let keychain = Keychain(service: "com.example.github-token") keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"

保存互联网密码

let keychain = Keychain(server: "https://github.com", protocolType: .https) keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"

:key: 实例化

创建用于应用程序密码的 Keychain

let keychain = Keychain(service: "com.example.github-token")
let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")

创建用于互联网密码的 Keychain

let keychain = Keychain(server: "https://github.com", protocolType: .https)
let keychain = Keychain(server: "https://github.com", protocolType: .https, authenticationType: .htmlForm)

:key: 添加项目

下标操作

对于字符串
keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
keychain[string: "kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
对于 NSData
keychain[data: "secret"] = NSData(contentsOfFile: "secret.bin")

set 方法

keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi")

错误处理

do { try keychain.set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print(error) }

:key: 获取项目

下标操作

对于字符串(如果值是 NSData,尝试转换为字符串)
let token = keychain["kishikawakatsumi"]
let token = keychain[string: "kishikawakatsumi"]
对于 NSData
let secretData = keychain[data: "secret"]

get 方法

作为字符串
let token = try? keychain.get("kishikawakatsumi")
let token = try? keychain.getString("kishikawakatsumi")
作为 NSData
let data = try? keychain.getData("kishikawakatsumi")

:key: 删除项目

下标操作

keychain["kishikawakatsumi"] = nil

remove 方法

do { try keychain.remove("kishikawakatsumi") } catch let error { print("error: \(error)") }

:key: 设置标签和注释

let keychain = Keychain(server: "https://github.com", protocolType: .https) do { try keychain .label("github.com (kishikawakatsumi)") .comment("github access token") .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print("error: \(error)") }

:key: 获取其他属性

持久引用

let keychain = Keychain() let persistentRef = keychain[attributes: "kishikawakatsumi"]?.persistentRef ...

创建日期

let keychain = Keychain() let creationDate = keychain[attributes: "kishikawakatsumi"]?.creationDate ...

所有属性

let keychain = Keychain() do { let attributes = try keychain.get("kishikawakatsumi") { $0 } print(attributes?.comment) print(attributes?.label) print(attributes?.creator) ... } catch let error { print("error: \(error)") }
下标操作
let keychain = Keychain() if let attributes = keychain[attributes: "kishikawakatsumi"] { print(attributes.comment) print(attributes.label) print(attributes.creator) }

:key: 配置(可访问性、共享、iCloud 同步)

提供流畅的接口

let keychain = Keychain(service: "com.example.github-token") .label("github.com (kishikawakatsumi)") .synchronizable(true) .accessibility(.afterFirstUnlock)

<a name="accessibility"> 可访问性

默认可访问性匹配后台应用程序(=kSecAttrAccessibleAfterFirstUnlock)
let keychain = Keychain(service: "com.example.github-token")
对于后台应用程序
创建实例
let keychain = Keychain(service: "com.example.github-token") .accessibility(.afterFirstUnlock) keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
一次性操作
let keychain = Keychain(service: "com.example.github-token") do { try keychain .accessibility(.afterFirstUnlock) .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print("error: \(error)") }
对于前台应用程序
创建实例
let keychain = Keychain(service: "com.example.github-token") .accessibility(.whenUnlocked) keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
一次性操作
let keychain = Keychain(service: "com.example.github-token") do { try keychain .accessibility(.whenUnlocked) .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print("error: \(error)") }

:couple: 共享 Keychain 项目

let keychain = Keychain(service: "com.example.github-token", accessGroup: "12ABCD3E4F.shared")

<a name="icloud_sharing"> :arrows_counterclockwise: 与iCloud同步钥匙串项目

创建实例
let keychain = Keychain(service: "com.example.github-token") .synchronizable(true) keychain["kishikawakatsumi"] = "01234567-89ab-cdef-0123-456789abcdef"
一次性操作
let keychain = Keychain(service: "com.example.github-token") do { try keychain .synchronizable(true) .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { print("错误: \(error)") }

<a name="touch_id_integration"> :cyclone: Touch ID (Face ID) 集成

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

要使用Face ID,请在Info.plist中添加NSFaceIDUsageDescription

:closed_lock_with_key: 添加受Touch ID (Face ID)保护的项目

如果你想存储受Touch ID保护的钥匙串项目,请指定accessibilityauthenticationPolicy属性。

let keychain = Keychain(service: "com.example.github-token") DispatchQueue.global().async { do { // 密码移除时是否应该使密钥失效?如果不需要,则使用`.WhenUnlocked` try keychain .accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: [.biometryAny]) .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { // 如需要,进行错误处理... } }

:closed_lock_with_key: 更新受Touch ID (Face ID)保护的项目

更新方式与添加时相同。

如果你尝试添加的项目可能已存在且受保护,请不要在主线程中运行。 因为更新受保护的项目需要认证。

此外,如果你想在更新时显示自定义认证提示信息,请指定authenticationPrompt属性。 如果项目未受保护,authenticationPrompt参数将被忽略。

let keychain = Keychain(service: "com.example.github-token") DispatchQueue.global().async { do { // 密码移除时是否应该使密钥失效?如果不需要,则使用`.WhenUnlocked` try keychain .accessibility(.whenPasscodeSetThisDeviceOnly, authenticationPolicy: [.biometryAny]) .authenticationPrompt("认证以更新你的访问令牌") .set("01234567-89ab-cdef-0123-456789abcdef", key: "kishikawakatsumi") } catch let error { // 如需要,进行错误处理... } }

:closed_lock_with_key: 获取受Touch ID (Face ID)保护的项目

获取方式与获取普通项目相同。如果你尝试获取的项目受保护,系统将自动显示Touch ID或密码认证。 如果你想显示自定义认证提示信息,请指定authenticationPrompt属性。 如果项目未受保护,authenticationPrompt参数将被忽略。

let keychain = Keychain(service: "com.example.github-token") DispatchQueue.global().async { do { let password = try keychain .authenticationPrompt("认证以登录服务器") .get("kishikawakatsumi") print("密码: \(password)") } catch let error { // 如需要,进行错误处理... } }

:closed_lock_with_key: 移除受Touch ID (Face ID)保护的项目

移除方式与移除普通项目相同。 移除钥匙串项目时无法显示Touch ID或密码认证。

let keychain = Keychain(service: "com.example.github-token") do { try keychain.remove("kishikawakatsumi") } catch let error { // 如需要,进行错误处理... }

<a name="shared_web_credentials"> :key: 共享Web凭证

共享Web凭证是一个编程接口,它使原生iOS应用能够与其网站对应部分共享凭证。例如,用户可能在Safari中登录网站,输入用户名和密码,并使用iCloud钥匙串保存这些凭证。之后,用户可能运行同一开发者的原生应用,应用不需要用户重新输入用户名和密码,共享Web凭证可以访问之前在Safari中输入的凭证。用户还可以在应用内创建新账户、更新密码或删除账户。这些更改随后会被保存并被Safari使用。 https://developer.apple.com/library/ios/documentation/Security/Reference/SharedWebCredentialsRef/

let keychain = Keychain(server: "https://www.kishikawakatsumi.com", protocolType: .HTTPS) let username = "kishikawakatsumi@mac.com" // 首先,检查应用的钥匙串中的凭证 if let password = try? keychain.get(username) { // 如果在钥匙串中找到密码, // 则登录服务器 } else { // 如果在钥匙串中未找到密码, // 尝试从共享Web凭证读取 keychain.getSharedPassword(username) { (password, error) -> () in if password != nil { // 如果在共享Web凭证中找到密码, // 则登录服务器 // 并将密码保存到钥匙串 keychain[username] = password } else { // 如果在钥匙串和共享Web凭证中都未找到密码, // 提示输入用户名和密码 // 登录服务器 // 如果登录成功, // 将凭证同时保存到钥匙串和共享Web凭证。 keychain[username] = inputPassword keychain.setSharedPassword(inputPassword, account: username) } } }

请求所有关联域的凭证

Keychain.requestSharedWebCredential { (credentials, error) -> () in }

生成强随机密码

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

let password = Keychain.generatePassword() // => Nhu-GKm-s3n-pMx

如何设置共享Web凭证

  1. 在你的应用中添加com.apple.developer.associated-domains授权。此授权必须包含你想要共享凭证的所有域。

  2. 在你的网站中添加apple-app-site-association文件。此文件必须包含网站想要共享凭证的所有应用的应用标识符,并且必须正确签名。

  3. 当应用安装时,系统会下载并验证每个关联域的站点关联文件。如果验证成功,应用就与该域关联。

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

:mag: 调试

打印钥匙串对象以显示所有存储的项目

let keychain = Keychain(server: "https://github.com", protocolType: .https) print("\(keychain)")
=>
[
  [authenticationType: default, key: kishikawakatsumi, server: github.com, class: internetPassword, protocol: https]
  [authenticationType: default, key: hirohamada, server: github.com, class: internetPassword, protocol: https]
  [authenticationType: default, key: honeylemon, server: github.com, class: internetPassword, protocol: https]
]

获取所有存储的键

let keychain = Keychain(server: "https://github.com", protocolType: .https) let keys = keychain.allKeys() for key in keys { print("键: \(key)") }
=>
键: kishikawakatsumi
键: hirohamada
键: honeylemon

获取所有存储的项目

let keychain = Keychain(server: "https://github.com", protocolType: .https) let items = keychain.allItems() for item in items { print("项目: \(item)") }
=>
项目: [authenticationType: Default, key: kishikawakatsumi, server: github.com, class: InternetPassword, protocol: https]
项目: [authenticationType: Default, key: hirohamada, server: github.com, class: InternetPassword, protocol: https]
项目: [authenticationType: Default, key: honeylemon, server: github.com, class: InternetPassword, protocol: https]

钥匙串共享功能

如果遇到以下错误,你需要添加一个Keychain.entitlements文件。

OSStatus error:[-34018] 内部错误,当所需的授权不存在时,客户端既没有application-identifier也没有keychain-access-groups授权。
<img alt="Screen Shot 2019-10-27 at 8 08 50" src="https://yellow-cdn.veclightyear.com/ab5030c0/f53c515c-7d81-4d14-8acb-34f8b9868e0c.png" width="500"> <img src="https://yellow-cdn.veclightyear.com/ab5030c0/e9cb96dc-5685-468e-8b44-3a9affa85db3.png" width="500" />

系统要求

操作系统Swift
v1.1.xiOS 7+, macOS 10.9+1.1
v1.2.xiOS 7+, macOS 10.9+1.2
v2.0.xiOS 7+, macOS 10.9+, watchOS 2+2.0
v2.1.xiOS 7+, macOS 10.9+, watchOS 2+2.0
v2.2.xiOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+2.0, 2.1
v2.3.xiOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+2.0, 2.1, 2.2
v2.4.xiOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+2.2, 2.3
v3.0.xiOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+3.x
v3.1.xiOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+4.0, 4.1, 4.2
v3.2.xiOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+4.0, 4.1, 4.2, 5.0
v4.0.xiOS 8+, macOS 10.9+, watchOS 2+, tvOS 9+4.0, 4.1, 4.2, 5.1
v4.1.xiOS 8+, macOS 10.9+, watchOS 3+, tvOS 9+, Mac Catalyst 13+4.0, 4.1, 4.2, 5.1

安装

CocoaPods

KeychainAccess 可通过 CocoaPods 获得。要安装它,只需在你的 Podfile 中添加以下几行:

use_frameworks! pod 'KeychainAccess'

Carthage

KeychainAccess 可通过 Carthage 获得。要安装它,只需在你的 Cartfile 中添加以下一行:

github "kishikawakatsumi/KeychainAccess"

Swift Package Manager

KeychainAccess 也可通过 Swift Package Manager 获得。

Xcode

选择 File > Add Packages... > Add Package Dependency...

<img src="https://yellow-cdn.veclightyear.com/ab5030c0/639326f4-7452-4f3e-8e74-39db38b43419.png" width="800px" />

命令行

首先,创建一个 Package.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/KeychainAccess.git", from: "3.0.0"), ], targets: [ .target(name: "MyLibrary", dependencies: ["KeychainAccess"]), ] )

然后,输入

$ swift build

手动添加到你的项目

  1. Lib/KeychainAccess.xcodeproj 添加到你的项目中
  2. KeychainAccess.framework 与你的目标链接
  3. 添加 Copy Files Build Phase 以将框架包含在你的应用程序包中

参考 iOS 示例项目

<img src="https://github.com/kishikawakatsumi/KeychainAccess/assets/40610/b7a46cfb-714d-47d5-84ea-6a80f640e03d" width="800px" />

作者

kishikawa katsumi, kishikawakatsumi@mac.com

许可证

KeychainAccess 在 MIT 许可下可用。有关更多信息,请参阅 LICENSE 文件。

编辑推荐精选

Vora

Vora

免费创建高清无水印Sora视频

Vora是一个免费创建高清无水印Sora视频的AI工具

Refly.AI

Refly.AI

最适合小白的AI自动化工作流平台

无需编码,轻松生成可复用、可变现的AI自动化工作流

酷表ChatExcel

酷表ChatExcel

大模型驱动的Excel数据处理工具

基于大模型交互的表格处理系统,允许用户通过对话方式完成数据整理和可视化分析。系统采用机器学习算法解析用户指令,自动执行排序、公式计算和数据透视等操作,支持多种文件格式导入导出。数据处理响应速度保持在0.8秒以内,支持超过100万行数据的即时分析。

AI工具酷表ChatExcelAI智能客服AI营销产品使用教程
TRAE编程

TRAE编程

AI辅助编程,代码自动修复

Trae是一种自适应的集成开发环境(IDE),通过自动化和多元协作改变开发流程。利用Trae,团队能够更快速、精确地编写和部署代码,从而提高编程效率和项目交付速度。Trae具备上下文感知和代码自动完成功能,是提升开发效率的理想工具。

AI工具TraeAI IDE协作生产力转型热门
AIWritePaper论文写作

AIWritePaper论文写作

AI论文写作指导平台

AIWritePaper论文写作是一站式AI论文写作辅助工具,简化了选题、文献检索至论文撰写的整个过程。通过简单设定,平台可快速生成高质量论文大纲和全文,配合图表、参考文献等一应俱全,同时提供开题报告和答辩PPT等增值服务,保障数据安全,有效提升写作效率和论文质量。

AI辅助写作AI工具AI论文工具论文写作智能生成大纲数据安全AI助手热门
博思AIPPT

博思AIPPT

AI一键生成PPT,就用博思AIPPT!

博思AIPPT,新一代的AI生成PPT平台,支持智能生成PPT、AI美化PPT、文本&链接生成PPT、导入Word/PDF/Markdown文档生成PPT等,内置海量精美PPT模板,涵盖商务、教育、科技等不同风格,同时针对每个页面提供多种版式,一键自适应切换,完美适配各种办公场景。

AI办公办公工具AI工具博思AIPPTAI生成PPT智能排版海量精品模板AI创作热门
潮际好麦

潮际好麦

AI赋能电商视觉革命,一站式智能商拍平台

潮际好麦深耕服装行业,是国内AI试衣效果最好的软件。使用先进AIGC能力为电商卖家批量提供优质的、低成本的商拍图。合作品牌有Shein、Lazada、安踏、百丽等65个国内外头部品牌,以及国内10万+淘宝、天猫、京东等主流平台的品牌商家,为卖家节省将近85%的出图成本,提升约3倍出图效率,让品牌能够快速上架。

iTerms

iTerms

企业专属的AI法律顾问

iTerms是法大大集团旗下法律子品牌,基于最先进的大语言模型(LLM)、专业的法律知识库和强大的智能体架构,帮助企业扫清合规障碍,筑牢风控防线,成为您企业专属的AI法律顾问。

SimilarWeb流量提升

SimilarWeb流量提升

稳定高效的流量提升解决方案,助力品牌曝光

稳定高效的流量提升解决方案,助力品牌曝光

Sora2视频免费生成

Sora2视频免费生成

最新版Sora2模型免费使用,一键生成无水印视频

最新版Sora2模型免费使用,一键生成无水印视频

下拉加载更多