最新国产好看的视频,伊人天堂AV在线,国产Aaaaaa视频,蜜臀视频在线观看一区,人妻av色图,密臀久久久精品影片,青青视频免费观看毛片,久草在线观看视,国产三级精品色情在线

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

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

正文

在我們開(kāi)發(fā)iOS應(yīng)用的時(shí)候,很多時(shí)候,我們都需要將敏感數(shù)據(jù)(password, accessToken, secretKey等)存儲(chǔ)到本地。對(duì)于初級(jí)程序員來(lái)講,首先映入腦海的可能是使用UserDefaults。然而,眾所周知,使用UserDefaults來(lái)存儲(chǔ)敏感信息簡(jiǎn)直是low的不能再low的主意了。因?yàn)槲覀円话愦鎯?chǔ)到UserDefaults中的數(shù)據(jù)都是未經(jīng)過(guò)編碼處理的,這樣是非常不安全的。

為了能安全的在本地存儲(chǔ)敏感信息,我們應(yīng)當(dāng)使用蘋(píng)果提供的KeyChain服務(wù)。這個(gè)framework已經(jīng)相當(dāng)老了,所以,我們?cè)诤竺骈喿x的時(shí)候,會(huì)覺(jué)得它提供的API并不像當(dāng)下的framework那么快捷。

在本文中,將為你展示如何創(chuàng)建一個(gè)通用的同時(shí)適用于iOS、MacOS的keyChain輔助類(lèi),對(duì)數(shù)據(jù)進(jìn)行增刪改查操作。開(kāi)始吧?。。?/p>

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

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

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

這個(gè)主意是為了創(chuàng)建一個(gè)query對(duì)象,這個(gè)對(duì)象包含了我們想要存儲(chǔ)最主要的數(shù)據(jù)鍵值對(duì)。然后,將query對(duì)象傳入SecItemAdd(_:_:)方法中來(lái)執(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對(duì)象由4個(gè)鍵值對(duì)組成:

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

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

創(chuàng)建完query對(duì)象之后,我們可以調(diào)用SecItemAdd(_:_:)方法來(lái)保存數(shù)據(jù)到keyChain。SecItemAdd(_:_:)方法會(huì)返回一個(gè)OSStatus來(lái)代表存儲(chǔ)狀態(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中使用,所以,上述代碼必須寫(xiě)在Controller中。

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

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

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

這時(shí)候,我們就無(wú)法將accessToken保存到keyChain中了。同時(shí),我們會(huì)得到一個(gè)Error: -25299的報(bào)錯(cuò)。該錯(cuò)誤碼代表的是存儲(chǔ)失敗。因?yàn)槲覀兯褂玫膋eys已經(jīng)存在于keyChain當(dāng)中了。

為了解決這個(gè)問(wèn)題,我們需要檢查這個(gè)錯(cuò)誤碼(相當(dāng)于errSecDuplicateItem),然后使用SecItemUpdate(_:_:)方法來(lái)更新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)建一個(gè)query對(duì)象,這個(gè)對(duì)象包含kSecAttrServicekSecAttrAccount。但是這次,我們將會(huì)創(chuàng)建另外一個(gè)包含kSecValueData的字典,并將它傳給SecItemUpdate(_:_:)方法。

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

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

從keyChain中讀取數(shù)據(jù)的方式和保存的方式非常相似。我們首先要做的是創(chuàng)建一個(gè)query對(duì)象,然后調(diào)用一個(gè)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對(duì)象的kSecAttrService and kSecAttrAccount的值。在這之前,我們需要為query對(duì)象添加一個(gè)新的鍵kSecReturnData,其值為true,代表的是我們希望query返回對(duì)應(yīng)項(xiàng)的數(shù)據(jù)。

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

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

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

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

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

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

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

創(chuàng)建一個(gè)通用的KeyChainHelper 類(lèi)

存儲(chǔ)

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的詳細(xì)內(nèi)容,更多關(guān)于iOS數(shù)據(jù)持久化KeyChain的資料請(qǐng)關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • iOS實(shí)現(xiàn)圓角箭頭矩形的提示框

    iOS實(shí)現(xiàn)圓角箭頭矩形的提示框

    不知道大家發(fā)現(xiàn)了沒(méi),在現(xiàn)在的很多App中常使用圓角箭頭矩形, 如微博分組提示框, 地圖坐標(biāo)顯示點(diǎn)等。iPad 中有 UIPopoverController 類(lèi)供開(kāi)發(fā)使用, iPhone中就需要開(kāi)發(fā)人員定制了。那么下面這篇文中就來(lái)聊聊定制圓角箭頭矩形提示框,有需要的朋友們可以參考借鑒。
    2016-11-11
  • iOS APP實(shí)現(xiàn)微信H5支付示例總結(jié)

    iOS APP實(shí)現(xiàn)微信H5支付示例總結(jié)

    這篇文章主要介紹了iOS APP實(shí)現(xiàn)微信H5支付示例總結(jié),文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • 簡(jiǎn)單講解Objective-C的基本特性及其內(nèi)存管理方式

    簡(jiǎn)單講解Objective-C的基本特性及其內(nèi)存管理方式

    這篇文章主要介紹了簡(jiǎn)單講解Objective-C的基本特性及其內(nèi)存管理方式,雖然Swift語(yǔ)言出現(xiàn)后iOS和Mac OS應(yīng)用開(kāi)發(fā)方面Objective-C正在成為過(guò)去時(shí),但現(xiàn)有諸多項(xiàng)目仍然在使用,需要的朋友可以參考下
    2016-01-01
  • Swift 去除 TableView 多余的空Cell中的橫線(xiàn)的方法

    Swift 去除 TableView 多余的空Cell中的橫線(xiàn)的方法

    這篇文章主要介紹了Swift 去除 TableView 多余的空Cell中的橫線(xiàn)的方法,文中通過(guò)示例代碼介紹的非常詳細(xì),對(duì)大家的學(xué)習(xí)或者工作具有一定的參考學(xué)習(xí)價(jià)值,需要的朋友們下面隨著小編來(lái)一起學(xué)習(xí)學(xué)習(xí)吧
    2020-02-02
  • iOS獲取圖片區(qū)域主色的方法

    iOS獲取圖片區(qū)域主色的方法

    這篇文章主要為大家詳細(xì)介紹了iOS獲取圖片區(qū)域主色的方法,文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2021-06-06
  • iOS CAReplicatorLayer實(shí)現(xiàn)脈沖動(dòng)畫(huà)效果

    iOS CAReplicatorLayer實(shí)現(xiàn)脈沖動(dòng)畫(huà)效果

    這篇文章主要介紹了iOS CAReplicatorLayer實(shí)現(xiàn)脈沖動(dòng)畫(huà)效果 ,具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2017-06-06
  • IOS程序開(kāi)發(fā)之禁止輸入表情符號(hào)實(shí)例代碼

    IOS程序開(kāi)發(fā)之禁止輸入表情符號(hào)實(shí)例代碼

    如何禁止輸入表情符號(hào)呢?下面腳本之家小編給大家分享IOS程序開(kāi)發(fā)之禁止輸入表情符號(hào)實(shí)例代碼,感興趣的朋友參考下吧
    2016-04-04
  • Objective-C實(shí)現(xiàn)冒泡排序算法的簡(jiǎn)單示例

    Objective-C實(shí)現(xiàn)冒泡排序算法的簡(jiǎn)單示例

    冒泡排序即是依次比較相鄰的兩個(gè)數(shù),如果后面的數(shù)較小則交換到前面一個(gè)數(shù)的位置上,這里我們來(lái)看一下Objective-C實(shí)現(xiàn)冒泡排序算法的簡(jiǎn)單示例
    2016-06-06
  • iOS 用Swipe手勢(shì)和動(dòng)畫(huà)實(shí)現(xiàn)循環(huán)播放圖片示例

    iOS 用Swipe手勢(shì)和動(dòng)畫(huà)實(shí)現(xiàn)循環(huán)播放圖片示例

    本篇文章主要介紹了iOS 用Swipe手勢(shì)和動(dòng)畫(huà)實(shí)現(xiàn)循環(huán)播放圖片示例,非常具有實(shí)用價(jià)值,需要的朋友可以參考下。
    2017-03-03
  • IOS微信端confirm以及alert去掉網(wǎng)址的實(shí)例代碼

    IOS微信端confirm以及alert去掉網(wǎng)址的實(shí)例代碼

    下面小編就為大家分享一篇IOS微信端confirm以及alert去掉網(wǎng)址的實(shí)例代碼,具有很好的參考價(jià)值,希望對(duì)大家有所幫助。一起跟隨小編過(guò)來(lái)看看吧
    2018-01-01

最新評(píng)論

资兴市| 汾阳市| 乌兰县| 广东省| 衢州市| 吴川市| 承德县| 唐河县| 页游| 蒙阴县| 青海省| 甘肃省| 涿鹿县| 浮山县| 左云县| 运城市| 米泉市| 夏邑县| 清水河县| 金昌市| 德兴市| 林西县| 渭南市| 怀安县| 纳雍县| 怀来县| 九龙坡区| 天门市| 乌拉特后旗| 广州市| 高陵县| 宁远县| 织金县| 宜兰市| 安宁市| 桓仁| 类乌齐县| 济南市| 大足县| 班戈县| 申扎县|