美文网首页OC-开发案例收集
[Swift] 钥匙串 Keychain 使用

[Swift] 钥匙串 Keychain 使用

作者: 巨馍蘸酱 | 来源:发表于2022-07-12 15:38 被阅读0次

    在 Swift 中使用钥匙串读取和保存密码

    Keychain 是适用于 macOS 和 iOS 的安全存储接口,最适合用于存储小块私人数据,例如密码、cookie 和身份验证令牌。

    SecItemAdd 将数据保存到钥匙串

    func SecItemAdd(_ attributes: CFDictionary, _ result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus

    SecItemAdd 用于将新项目保存到 Keychain。

    • kSecAttrService 一个字符串,用于标识一组钥匙串项目,如 com.my-app.bundle-id
    • kSetAttrAccount 一个字符串,用于标识特定服务中的钥匙串项,例如 username`@email.com
    • kSecClass 一种存储在 Keychain Item 中的安全数据,例如 kSecClassGenericPassword

    第二个参数 result 是 UnsafeMutablePointer 查询指定的任何返回值。通常不需要返回数据,并且nil可以传递结果。

    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 更新钥匙串中的数据

    func SecItemUpdate(_ query: CFDictionary, _ attributesToUpdate: CFDictionary) -> OSStatus

    SecItemUpdate 用于覆盖 Keychain 中的现有 kSecValueData 数据。

    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 从钥匙串中读取数据

    func SecItemCopyMatching(_ query: CFDictionary, _ result: UnsafeMutablePointer<CFTypeRef?>?) -> OSStatus

    就像 SecItemAdd ,SecItemCopyMatching 方法有一个 UnsafeMutablePointer 参数和一个 query 参数。读取的数据 SecItemCopyMatching 将被复制到 UnsafeMutablePointer result 供 macOS 和 iOS 应用程序访问。

    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 删除钥匙串中的数据

    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 钥匙串同步,则可以自动将用户的钥匙串数据与该用户的 iCloud 同步。为此,请在为所有钥匙串操作构造钥匙串服务查询时设置 kSecAttrSynchronizablekCFBooleanTrue

    query[kSecAttrSynchronizable as String] = kCFBooleanTrue

    原文 https://www.advancedswift.com/secure-private-data-keychain-swift

    相关文章

      网友评论

        本文标题:[Swift] 钥匙串 Keychain 使用

        本文链接:https://www.haomeiwen.com/subject/bkhtirtx.html