我在将可用于添加数据和从Objective C查询数据的所有iOS Keychain代码样本转换为 Swift 时遇到了麻烦。我正在尝试对字符串(访问 token )进行基本存储,然后将其读回。我看过关于Stack Overflow的其他一些问题,但是我不能完全解决它。我试图从各种来源整理出一个解决方案。

编辑1:我尝试了更基本的设置,因为我认为我的self.defaultKeychainQuery可能已经搞砸了。我已经将下面的代码更新为最新版本。

编辑2:使它正常工作。我没有将数据值正确添加到保存查询中。我需要将字符串转换为NSData。我已经将下面的代码更新为最新的工作版本。

编辑3:正如Xerxes指出的那样,由于Dictionary的某些问题,此代码不适用于高于Beta 1的Xcode版本。如果您知道解决方法,请告诉我。

更新:我把它变成了keychain library written in Swift called Locksmith

保存

class func save(service: NSString, data: NSString) {
  var dataFromString: NSData = data.dataUsingEncoding(NSUTF8StringEncoding, allowLossyConversion: false)
  // Instantiate a new default keychain query
  var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, userAccount, dataFromString], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecValueData])

  // Delete any existing items
  SecItemDelete(keychainQuery as CFDictionaryRef)

  // Add the new keychain item
  var status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil)

  // Check that it worked ok
  println("Saving status code is: \(status)")
}

加载
  class func load(service: NSString) -> AnyObject? {
    // Instantiate a new default keychain query
    // Tell the query to return a result
    // Limit our results to one item
    var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPassword, service, userAccount, kCFBooleanTrue, kSecMatchLimitOne], forKeys: [kSecClass, kSecAttrService, kSecAttrAccount, kSecReturnData, kSecMatchLimit])



    // I'm not too sure what's happening here...
    var dataTypeRef :Unmanaged<AnyObject>?

    // Search for the keychain items
    let status: OSStatus = SecItemCopyMatching(keychainQuery, &dataTypeRef)


    println("Loading status code is: \(status)")

    // I'm not too sure what's happening here...
    let opaque = dataTypeRef?.toOpaque()

    if let op = opaque? {
      let retrievedData = Unmanaged<NSData>.fromOpaque(op).takeUnretainedValue()
      println("Retrieved the following data from the keychain: \(retrievedData)")
      var str = NSString(data: retrievedData, encoding: NSUTF8StringEncoding)
      println("The decoded string is \(str)")
    } else {
      println("Nothing was retrieved from the keychain.")
    }

    return nil
  }

用法( View Controller )
KeychainService.saveToken("sometoken")
KeychainService.loadToken()

使用这些便捷方法
class func saveToken(token: NSString) {
    self.save("service", data: token)
  }

class func loadToken() {
    var token = self.load("service")
    if let t = token {
      println("The token is: \(t)")
    }
  }

这导致控制台中的输出:
Saving status code is: 0
Loading status code is: 0
Retrieved the following data from the keychain: <736f6d65 746f6b65 6e>
The decoded string is sometoken

非常感谢你的帮助。我不太确定一旦获得dataTypeRef或上面给出的代码中是否包含任何数据,该怎么办。

最佳答案

为了使它起作用,您将需要检索钥匙串(keychain)常量的保留值,然后首先存储,如下所示:

let kSecClassValue = kSecClass.takeRetainedValue() as NSString
let kSecAttrAccountValue = kSecAttrAccount.takeRetainedValue() as NSString
let kSecValueDataValue = kSecValueData.takeRetainedValue() as NSString
let kSecClassGenericPasswordValue = kSecClassGenericPassword.takeRetainedValue() as NSString
let kSecAttrServiceValue = kSecAttrService.takeRetainedValue() as NSString
let kSecMatchLimitValue = kSecMatchLimit.takeRetainedValue() as NSString
let kSecReturnDataValue = kSecReturnData.takeRetainedValue() as NSString
let kSecMatchLimitOneValue = kSecMatchLimitOne.takeRetainedValue() as NSString

然后,您可以像这样在NSMutableDictionary中引用值:
var keychainQuery: NSMutableDictionary = NSMutableDictionary(objects: [kSecClassGenericPasswordValue, service, userAccount, kCFBooleanTrue, kSecMatchLimitOneValue], forKeys: [kSecClassValue, kSecAttrServiceValue, kSecAttrAccountValue, kSecReturnDataValue, kSecMatchLimitValue])

我在以下位置写了一篇有关它的博客文章:
http://rshelby.com/2014/08/using-swift-to-save-and-query-ios-keychain-in-xcode-beta-4/

希望这可以帮助!

舍尔比

关于ios - 使用Swift向iOS钥匙串(keychain)添加项目和查询,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/24324285/

10-13 01:03