在 Swift 中使用鑰匙串讀取和保存密碼
Keychain 是適用于 macOS 和 iOS 的安全存儲接口,最適合用于存儲小塊私人數(shù)據(jù),例如密碼、cookie 和身份驗(yàn)證令牌。
SecItemAdd 將數(shù)據(jù)保存到鑰匙串
func SecItemAdd(_ attributes: CFDictionary, _ result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus
SecItemAdd 用于將新項(xiàng)目保存到 Keychain。
-
kSecAttrService
一個字符串,用于標(biāo)識一組鑰匙串項(xiàng)目,如 com.my-app.bundle-id -
kSetAttrAccount
一個字符串,用于標(biāo)識特定服務(wù)中的鑰匙串項(xiàng),例如 username`@email.com -
kSecClass
一種存儲在 Keychain Item 中的安全數(shù)據(jù),例如 kSecClassGenericPassword
第二個參數(shù) result
是 UnsafeMutablePointer 查詢指定的任何返回值。通常不需要返回數(shù)據(jù),并且nil可以傳遞結(jié)果。
static func save(password: Data, service: String, account: String) -> Bool {
let query: [String: AnyObject] = [
// kSecAttrService, kSecAttrAccount, and kSecClass
// uniquely identify the item to save in Keychain
kSecAttrService as String: service as AnyObject,
kSecAttrAccount as String: account as AnyObject,
kSecClass as String: kSecClassGenericPassword,
// kSecValueData is the item value to save
kSecValueData as String: password as AnyObject
]
// SecItemAdd attempts to add the item identified by
// the query to keychain
let status = SecItemAdd(query as CFDictionary, nil)
// Any status other than errSecSuccess indicates the
// save operation failed.
return status == errSecSuccess
}
SecItemUpdate 更新鑰匙串中的數(shù)據(jù)
func SecItemUpdate(_ query: CFDictionary, _ attributesToUpdate: CFDictionary) -> OSStatus
SecItemUpdate
用于覆蓋 Keychain 中的現(xiàn)有 kSecValueData
數(shù)據(jù)。
static func update(password: Data, service: String, account: String) -> Bool {
let query: [String: AnyObject] = [
// kSecAttrService, kSecAttrAccount, and kSecClass
// uniquely identify the item to update in Keychain
kSecAttrService as String: service as AnyObject,
kSecAttrAccount as String: account as AnyObject,
kSecClass as String: kSecClassGenericPassword
]
// attributes is passed to SecItemUpdate with
// kSecValueData as the updated item value
let attributes: [String: AnyObject] = [
kSecValueData as String: password as AnyObject
]
// SecItemUpdate attempts to update the item identified
// by query, overriding the previous value
let status = SecItemUpdate(
query as CFDictionary,
attributes as CFDictionary
)
// Any status other than errSecSuccess indicates the
// update operation failed.
return status == errSecSuccess
}
SecItemCopyMatching 從鑰匙串中讀取數(shù)據(jù)
func SecItemCopyMatching(_ query: CFDictionary, _ result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus
就像 SecItemAdd ,SecItemCopyMatching 方法有一個 UnsafeMutablePointer 參數(shù)和一個 query 參數(shù)。讀取的數(shù)據(jù) SecItemCopyMatching 將被復(fù)制到 UnsafeMutablePointer result 供 macOS 和 iOS 應(yīng)用程序訪問。
static func readPassword(service: String, account: String) -> Data? {
let query: [String: AnyObject] = [
// kSecAttrService, kSecAttrAccount, and kSecClass
// uniquely identify the item to read in Keychain
kSecAttrService as String: service as AnyObject,
kSecAttrAccount as String: account as AnyObject,
kSecClass as String: kSecClassGenericPassword,
// kSecMatchLimitOne indicates keychain should read
// only the most recent item matching this query
kSecMatchLimit as String: kSecMatchLimitOne,
// kSecReturnData is set to kCFBooleanTrue in order
// to retrieve the data for the item
kSecReturnData as String: kCFBooleanTrue
]
// SecItemCopyMatching will attempt to copy the item
// identified by query to the reference itemCopy
var itemCopy: AnyObject?
let status = SecItemCopyMatching(query as CFDictionary, &itemCopy)
// Any status other than errSecSuccess indicates the
// read operation failed.
guard status == errSecSuccess else {
return nil
}
// This implementation of KeychainInterface requires all
// items to be saved and read as Data. Otherwise,
// invalidItemFormat is thrown
guard let password = itemCopy as? Data else {
throw nil
}
return password
}
SecItemDelete 刪除鑰匙串中的數(shù)據(jù)
func SecItemDelete(_ query: CFDictionary) -> OSStatus
static func deletePassword(service: String, account: String) -> Bool {
let query: [String: AnyObject] = [
// kSecAttrService, kSecAttrAccount, and kSecClass
// uniquely identify the item to delete in Keychain
kSecAttrService as String: service as AnyObject,
kSecAttrAccount as String: account as AnyObject,
kSecClass as String: kSecClassGenericPassword
]
// SecItemDelete attempts to perform a delete operation
// for the item identified by query. The status indicates
// if the operation succeeded or failed.
let status = SecItemDelete(query as CFDictionary)
// Any status other than errSecSuccess indicates the
// delete operation failed.
return status == errSecSuccess
}
與 iCloud 同步鑰匙串
如果啟用了 iCloud 鑰匙串同步,則可以自動將用戶的鑰匙串?dāng)?shù)據(jù)與該用戶的 iCloud 同步。為此,請在為所有鑰匙串操作構(gòu)造鑰匙串服務(wù)查詢時設(shè)置 kSecAttrSynchronizable
為 kCFBooleanTrue
query[kSecAttrSynchronizable as String] = kCFBooleanTrue