Published on

Keychain β€” maxfiy ma'lumotlarni xavfsiz saqlash

Authors

Parollar, API tokenlar, maxfiy kalitlar β€” bularni UserDefaults da saqlash XAVFLI. Keychain β€” Apple ning shifrlangan xavfsiz ombori.

Keychain Wrapper yaratish

import Foundation
import Security

// ═══════════════════════════════════════
//  KEYCHAIN MENEJERI β€” soddalashtirilgan API
// ═══════════════════════════════════════
class KeychainMenejer {

    // Saqlash
    static func saqlash(kalit: String, ma'lumot: String) -> Bool {
        // String ni Data ga aylantirish
        guard let data = ma'lumot.data(using: .utf8) else { return false }

        // Avval eski qiymatni o'chirish (yangilash uchun)
        oChirish(kalit: kalit)

        // Query β€” Keychain ga qanday saqlash
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: kalit,     // Kalit (identifikator)
            kSecValueData as String: data,          // Qiymat (shifrlangan)
        ]

        // Keychain ga qo'shish
        let status = SecItemAdd(query as CFDictionary, nil)
        return status == errSecSuccess
    }

    // O'qish
    static func olish(kalit: String) -> String? {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: kalit,
            kSecReturnData as String: true,          // Ma'lumotni qaytar
            kSecMatchLimit as String: kSecMatchLimitOne, // Bitta natija
        ]

        var natija: AnyObject?
        let status = SecItemCopyMatching(query as CFDictionary, &natija)

        guard status == errSecSuccess,
              let data = natija as? Data,
              let matn = String(data: data, encoding: .utf8)
        else { return nil }

        return matn
    }

    // O'chirish
    @discardableResult
    static func oChirish(kalit: String) -> Bool {
        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: kalit,
        ]
        let status = SecItemDelete(query as CFDictionary)
        return status == errSecSuccess
    }

    // Yangilash
    static func yangilash(kalit: String, yangiMalumot: String) -> Bool {
        guard let data = yangiMalumot.data(using: .utf8) else { return false }

        let query: [String: Any] = [
            kSecClass as String: kSecClassGenericPassword,
            kSecAttrAccount as String: kalit,
        ]
        let yangilanish: [String: Any] = [
            kSecValueData as String: data,
        ]

        let status = SecItemUpdate(
            query as CFDictionary,
            yangilanish as CFDictionary
        )
        return status == errSecSuccess
    }
}

Ishlatish

// ═══════════════════════════════════════
//  AMALIY ISHLATISH
// ═══════════════════════════════════════

// API token saqlash
KeychainMenejer.saqlash(kalit: "api_token", ma'lumot: "abc123xyz")

// Token o'qish
if let token = KeychainMenejer.olish(kalit: "api_token") {
    print("Token: \(token)")
}

// Token yangilash
KeychainMenejer.yangilash(kalit: "api_token", yangiMalumot: "yangi_token_456")

// Token o'chirish (logout)
KeychainMenejer.oChirish(kalit: "api_token")


// ═══════════════════════════════════════
//  SWIFTUI BILAN ISHLATISH
// ═══════════════════════════════════════
class AuthViewModel: ObservableObject {
    @Published var tizimgaKirgan = false

    init() {
        // Ilova ochilganda token bor-yo'qligini tekshirish
        tizimgaKirgan = KeychainMenejer.olish(kalit: "auth_token") != nil
    }

    func kirish(email: String, parol: String) async {
        // Tarmoq so'rovi β€” token olish
        let token = "server_dan_kelgan_token"

        // βœ… Token ni Keychain da saqlash
        KeychainMenejer.saqlash(kalit: "auth_token", ma'lumot: token)

        await MainActor.run {
            tizimgaKirgan = true
        }
    }

    func chiqish() {
        // βœ… Token ni Keychain dan o'chirish
        KeychainMenejer.oChirish(kalit: "auth_token")
        tizimgaKirgan = false
    }
}

Nima qayerda saqlash kerak

Ma'lumotSaqlash joyiSabab
Parol, Tokenβœ… KeychainShifrlangan, xavfsiz
Foydalanuvchi sozlamalariUserDefaults / @AppStorageMaxfiy emas
Katta ma'lumotSwiftData / CoreDataTuzilgan ma'lumotlar bazasi
FayllarFileManagerRasm, video, hujjat

🎯 Topshiriq

AuthViewModel yarating: kirish(email:parol:), chiqish(), tokenBormi(). Keychain da "auth_token" saqlang. SwiftUI da login/logout ekran yarating β€” token bo'lsa asosiy ekran, bo'lmasa login.

Buy mea coffee