欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

iOS數(shù)據(jù)持久化KeyChain數(shù)據(jù)操作詳解

 更新時間:2023年02月03日 14:26:06   作者:莊周曉夢  
這篇文章主要為大家介紹了iOS數(shù)據(jù)持久化KeyChain,有需要的朋友可以借鑒參考下,希望能夠有所幫助,祝大家多多進步,早日升職加薪

正文

在我們開發(fā)iOS應(yīng)用的時候,很多時候,我們都需要將敏感數(shù)據(jù)(password, accessToken, secretKey等)存儲到本地。對于初級程序員來講,首先映入腦海的可能是使用UserDefaults。然而,眾所周知,使用UserDefaults來存儲敏感信息簡直是low的不能再low的主意了。因為我們一般存儲到UserDefaults中的數(shù)據(jù)都是未經(jīng)過編碼處理的,這樣是非常不安全的。

為了能安全的在本地存儲敏感信息,我們應(yīng)當使用蘋果提供的KeyChain服務(wù)。這個framework已經(jīng)相當老了,所以,我們在后面閱讀的時候,會覺得它提供的API并不像當下的framework那么快捷。

在本文中,將為你展示如何創(chuàng)建一個通用的同時適用于iOS、MacOS的keyChain輔助類,對數(shù)據(jù)進行增刪改查操作。開始吧?。?!

保存數(shù)據(jù)到KeyChain

final class KeyChainHelper {
    static let standard = KeyChainHelper()
    private init(){}
}

我們必須巧妙使用SecItemAdd(_:_:)方法,這個方法會接收一個CFDictionary類型的query對象。

這個主意是為了創(chuàng)建一個query對象,這個對象包含了我們想要存儲最主要的數(shù)據(jù)鍵值對。然后,將query對象傳入SecItemAdd(_:_:)方法中來執(zhí)行保存操作。

func save(_ data: Data, service: String, account: String) {
    // Create query
    let query = [
        kSecValueData: data,
        kSecClass: kSecClassGenericPassword,
        kSecAttrService: service,
        kSecAttrAccount: account,
    ] as CFDictionary
    // Add data in query to keychain
    let status = SecItemAdd(query, nil)
    if status != errSecSuccess {
        // Print out the error
        print("Error: (status)")
    }
}

回看上述代碼片段,query對象由4個鍵值對組成:

  • kSecValueData: 這個鍵代表著數(shù)據(jù)已經(jīng)被存儲到了keyChain中
  • kSecClass: 這個鍵代表著數(shù)據(jù)已經(jīng)被存儲到了keyChain中。我們將它的值設(shè)為了kSecClassGenericPassword,這代表著我們所保存的數(shù)據(jù)是一個通用的密碼項
  • kSecAttrServicekSecAttrAccount: 當kSecClass被設(shè)置為kSecClassGenericPassword的時候,kSecAttrServicekSecAttrAccount這兩個鍵是必須要有的。這兩個鍵所對應(yīng)的值將作為所保存數(shù)據(jù)的關(guān)鍵key,換句話說,我們將使用他們從keyChain中讀取所保存的值。

對于kSecAttrServicekSecAttrAccount所對應(yīng)的值的定義并沒有什么難的。推薦使用字符串。例如:如果我們想存儲Facebook的accesToken,我們需要將kSecAttrService設(shè)置成”access-token“,將kSecAttrAccount設(shè)置成”facebook“

創(chuàng)建完query對象之后,我們可以調(diào)用SecItemAdd(_:_:)方法來保存數(shù)據(jù)到keyChain。SecItemAdd(_:_:)方法會返回一個OSStatus來代表存儲狀態(tài)。如果我們得到的是errSecSuccess狀態(tài),則意味著數(shù)據(jù)已經(jīng)被成功保存到keyChain中

下面是save(_:service:account:)方法的使用

let accessToken = "dummy-access-token"
let data = Data(accessToken.utf8)
KeychainHelper.standard.save(data, service: "access-token", account: "facebook")

keyChain不能在playground中使用,所以,上述代碼必須寫在Controller中。

更新KeyChain中已有的數(shù)據(jù)

現(xiàn)在我們有了save(_:service:account:)方法,讓我們用相同的kSecAttrServicekSecAttrAccount所對應(yīng)的值來存儲其他token

let accessToken = "another-dummy-access-token"
let data = Data(accessToken.utf8)
KeychainHelper.standard.save(data, service: "access-token", account: "facebook")

這時候,我們就無法將accessToken保存到keyChain中了。同時,我們會得到一個Error: -25299的報錯。該錯誤碼代表的是存儲失敗。因為我們所使用的keys已經(jīng)存在于keyChain當中了。

為了解決這個問題,我們需要檢查這個錯誤碼(相當于errSecDuplicateItem),然后使用SecItemUpdate(_:_:)方法來更新keyChain。一起看看并更新我們前述的save(_:service:account:)方法吧:

func save(_ data: Data, service: String, account: String) {
    // ... ...
    // ... ...
    if status == errSecDuplicateItem {
        // Item already exist, thus update it.
        let query = [
            kSecAttrService: service,
            kSecAttrAccount: account,
            kSecClass: kSecClassGenericPassword,
        ] as CFDictionary
        let attributesToUpdate = [kSecValueData: data] as CFDictionary
        // Update existing item
        SecItemUpdate(query, attributesToUpdate)
    }
}

跟保存操作相似的是,我們需要先創(chuàng)建一個query對象,這個對象包含kSecAttrServicekSecAttrAccount。但是這次,我們將會創(chuàng)建另外一個包含kSecValueData的字典,并將它傳給SecItemUpdate(_:_:)方法。

這樣的話,我們就可以讓save(_:service:account:)方法來更新keyChain中已有的數(shù)據(jù)了。

從KeyChain中讀取數(shù)據(jù)

從keyChain中讀取數(shù)據(jù)的方式和保存的方式非常相似。我們首先要做的是創(chuàng)建一個query對象,然后調(diào)用一個keyChain方法:

func read(service: String, account: String) -> Data? {
    let query = [
        kSecAttrService: service,
        kSecAttrAccount: account,
        kSecClass: kSecClassGenericPassword,
        kSecReturnData: true
    ] as CFDictionary
    var result: AnyObject?
    SecItemCopyMatching(query, &result)
    return (result as? Data)
}

跟之前一樣,我們需要設(shè)置query對象的kSecAttrService and kSecAttrAccount的值。在這之前,我們需要為query對象添加一個新的鍵kSecReturnData,其值為true,代表的是我們希望query返回對應(yīng)項的數(shù)據(jù)。

之后,我們將利用 SecItemCopyMatching(_:_:) 方法并通過引用傳入 AnyObject 類型的result對象。SecItemCopyMatching(_:_:)方法同樣返回一個OSStatus類型的值,代表讀取操作狀態(tài)。但是如果讀取失敗了,這里我們不做任何校驗,并返回nil

讓keyChain支持讀取的操作就這么多了,看一下他是怎么工作的吧

let data = KeychainHelper.standard.read(service: "access-token", account: "facebook")!
let accessToken = String(data: data, encoding: .utf8)!
print(accessToken)

從KeyChain中刪除數(shù)據(jù)

如果沒有刪除操作,我們的KeyChainHelper類并不算完成。一起看看下面的代碼片段吧

func delete(service: String, account: String) {
    let query = [
        kSecAttrService: service,
        kSecAttrAccount: account,
        kSecClass: kSecClassGenericPassword,
        ] as CFDictionary
    // Delete item from keychain
    SecItemDelete(query)
}

如果你全程都在看的話,上述代碼可能對你來說非常熟悉,那是相當?shù)?rdquo;自解釋“了,需要注意的是,這里我們使用了SecItemDelete(_:)方法來刪除KeyChain中的數(shù)據(jù)了。

創(chuàng)建一個通用的KeyChainHelper 類

存儲

func save<T>(_ item: T, service: String, account: String) where T : Codable {
    do {
        // Encode as JSON data and save in keychain
        let data = try JSONEncoder().encode(item)
        save(data, service: service, account: account)
    } catch {
        assertionFailure("Fail to encode item for keychain: (error)")
    }
}

讀取

func read<T>(service: String, account: String, type: T.Type) -> T? where T : Codable {
    // Read item data from keychain
    guard let data = read(service: service, account: account) else {
        return nil
    }
    // Decode JSON data to object
    do {
        let item = try JSONDecoder().decode(type, from: data)
        return item
    } catch {
        assertionFailure("Fail to decode item for keychain: \(error)")
        return nil
    }
}

使用

struct Auth: Codable {
    let accessToken: String
    let refreshToken: String
}
// Create an object to save
let auth = Auth(accessToken: "dummy-access-token",
                 refreshToken: "dummy-refresh-token")
let account = "domain.com"
let service = "token"
// Save `auth` to keychain
KeychainHelper.standard.save(auth, service: service, account: account)
// Read `auth` from keychain
let result = KeychainHelper.standard.read(service: service,
                                          account: account,
                                          type: Auth.self)!
print(result.accessToken)   // Output: "dummy-access-token"
print(result.refreshToken)  // Output: "dummy-refresh-token"

以上就是iOS數(shù)據(jù)持久化KeyChain的詳細內(nèi)容,更多關(guān)于iOS數(shù)據(jù)持久化KeyChain的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • iOS CoreAnimation 圖層幾何學(xué)

    iOS CoreAnimation 圖層幾何學(xué)

    本文主要介紹了iOS CoreAnimation圖層幾何學(xué),圖層幾何所講主要是有關(guān)圖層的位置,尺寸等幾何類屬性。具有很好的參考價值。下面跟著小編一起來看下吧
    2017-03-03
  • swift 常用高階函數(shù)分享

    swift 常用高階函數(shù)分享

    Swift是一門面向協(xié)議的語言,在使用Swift時我們已經(jīng)充分享受到了面向協(xié)議編程帶給我們的便利,但是Swift相比Obj-C還有一個更重要的優(yōu)點,那就是對函數(shù)式編程提供了很好的支持,其中Swift提供了map,filter,reduce這三個高階函數(shù)Higher Order function作為對容器的支持
    2017-12-12
  • iOS關(guān)聯(lián)對象示例詳解

    iOS關(guān)聯(lián)對象示例詳解

    這篇文章主要給大家介紹了關(guān)于iOS關(guān)聯(lián)對象的相關(guān)資料,文中通過示例代碼結(jié)束的非常詳細,對大家學(xué)習(xí)或者使用iOS具有一定的參考學(xué)習(xí)價值,需要的朋友們下面隨著小編來一起學(xué)習(xí)學(xué)習(xí)吧
    2018-12-12
  • IOS 開發(fā)之 UITextField限制字數(shù)的方法

    IOS 開發(fā)之 UITextField限制字數(shù)的方法

    這篇文章主要介紹了IOS 開發(fā)之 UITextField限制字數(shù)的方法的相關(guān)資料,這里提供實現(xiàn)限制最大字數(shù)的方法,需要的朋友可以參考下
    2017-08-08
  • iOS實時錄音和播放功能

    iOS實時錄音和播放功能

    這篇文章主要為大家詳細介紹了iOS實時錄音和播放功能,具有一定的參考價值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • IOS開發(fā)過程中的消息通知--小紅點

    IOS開發(fā)過程中的消息通知--小紅點

    本文主要介紹了IOS開發(fā)過程中的消息通知--小紅點的相關(guān)知識。大致分為兩種方法:系統(tǒng)方法和自定義方法。下面跟著小編一起來看下吧
    2017-04-04
  • iOS實現(xiàn)“搖一搖”與“掃一掃”功能示例代碼

    iOS實現(xiàn)“搖一搖”與“掃一掃”功能示例代碼

    本篇文章主要介紹了iOS實現(xiàn)“搖一搖”與“掃一掃”功能示例代碼,具有一定的參考價值,有興趣的可以了解一下。
    2017-01-01
  • iOS實現(xiàn)相冊和網(wǎng)絡(luò)圖片的存取

    iOS實現(xiàn)相冊和網(wǎng)絡(luò)圖片的存取

    本篇文章主要介紹了iOS實現(xiàn)相冊和網(wǎng)絡(luò)圖片的存取,小編覺得挺不錯的,現(xiàn)在分享給大家,也給大家做個參考。一起跟隨小編過來看看吧
    2017-04-04
  • iOS APP中保存圖片到相冊時崩潰的解決方法

    iOS APP中保存圖片到相冊時崩潰的解決方法

    下面小編就為大家分享一篇iOS APP中保存圖片到相冊時崩潰的解決方法,具有很好的參考價值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2017-12-12
  • 詳解iOS集成GoogleMap(定位、搜索)

    詳解iOS集成GoogleMap(定位、搜索)

    這篇文章主要介紹了iOS集成GoogleMap(定位、搜索)需要注意的地方,對此有興趣的讀者一起學(xué)習(xí)下吧。
    2018-02-02

最新評論