代码之家  ›  专栏  ›  技术社区  ›  Braden Holt

使用Swift向iOS上的Keychain添加身份验证凭据

  •  0
  • Braden Holt  · 技术社区  · 6 年前

    kSecClassKey 以及中的用户id kSecAttrAccount

    编辑:我想我只是用错了钥匙链。这感觉不对。如果有人有任何建议,我知道,但我可能会删除这个很快。

    代码如下所示:

    loginUser() {
        ...
        let account = user_id
        let server = "www.foo.com"
        let token = auth_token
    
        let query: [String: Any] = [
            kSecClass as String: kSecClassInternetPassword,
            kSecAttrAccount as String: account,
            kSecAttrServer as String: server,
            kSecClassKey as String: token
        ]
    
        let status = SecItemAdd(query as CFDictionary, nil)
    
        print(status)
    }
    

    -50 . 这个代码可能意味着根据 osstatus 包括 errSecNoSuchClass , errSecUseKeychainListUnsupported errSecUseKeychainUnsupported .

    我在跟踪 this tutorial

    1 回复  |  直到 6 年前
        1
  •  3
  •   Brandon    6 年前


    首先,您需要创建一个函数来检查该项是否已经存在。。 如果存在,则需要“更新”该项。如果它不存在,你需要添加它。。

    应使用以下代码(Swift 4.2)。。也不需要将数据存储为Internet密码。。您可以将其存储为通用密码。。但这完全取决于你。

    我在下面使用了通用密码,我只是存储了一个以“user”为键的字典。

    static let keychainIdentifier = "com.myproject.keychain.identifier"
    
    // Checks if an item exists in the keychain already..
    func exists(key: String, completion: @escaping (_ error: OSStatus, _ query: [CFString: Any], _ result: [CFString: Any]?) -> Void) {
        var query: [CFString: Any] = [
            kSecClass: kSecClassGenericPassword,
            kSecAttrGeneric: keychainIdentifier.data(using: .utf8)!
            kSecMatchLimit: kSecMatchLimitOne,
            kSecReturnAttributes: kCFBooleanTrue,
            kSecAttrAccessible: kSecAttrAccessibleWhenUnlockedThisDeviceOnly,
            kSecAttrAccount: key
        ]
    
        var result: CFTypeRef?
        let error = SecItemCopyMatching(accountQuery as CFDictionary, &result)
        completion(error, accountQuery, result as? [CFString: Any])
    }
    
    // Adds or Updates an item in the keychain..
    func setItem(key: String, data: Data) throws {
        exists(key: key) { error, query, _ in
            var query = query
            query[kSecMatchLimit] = nil
            query[kSecReturnAttributes] = nil
    
            if error == noErr || error == errSecDuplicateItem || error == errSecInteractionNotAllowed {
                let updateQuery = [kSecValueData: data]
                let err = SecItemUpdate(query as CFDictionary, updateQuery as CFDictionary)
                if err != noErr {
                    throw KeychainError((code: err, message: "Cannot Update Item")
                }
            } 
            else if error == errSecItemNotFound {
                query[kSecValueData] = data
                let err = SecItemAdd(query as CFDictionary, nil)
                if err != noErr {
                    throw KeychainError((code: err, message: "Cannot Set Item")
                }
            } else {
                if err != noErr {
                    throw KeychainError(code: err, message: "Error Occurred")
                }
            }
        }
    }
    
    // Convenience function to save JSON to the keychain
    func setItem(key: String, data: Codable) throws {
        let encodedData = try JSONEncoder().encode(data)
        setItem(key: key, data: encodedData)
    }
    

    struct User: Codable {
        let username: String
        let token: String?
        let otherInfo: String
    }
    
    let user = User(username: "Brandon", token: "...", otherInfo: "...")
    setItem(key: user.username, data: user)
    

    或者,如果只是代币,那么:

    setItem(key: user.username, data: "...".data(using: .utf8)!)