訪問KeyChain
1.在mac上按下 Command+Space 輸入Keychain Access
2.在終端輸入security find-generic-password -help
讀取配置文件授權
cd ~/Desktop
//ios產看應用的授權來發現他需要的訪問類型,應用的授權以編碼的形式保存在對應的簽名的配置文件中,嘉定已經創建一個配置文件,名為KeycahinTest_Dev.mobileprovision並且保存在桌面
security cms -D -i KeychainTest_Dev.mobileprovision | grep -A12 “Entitlements”
keychain-acess-groups 定義同一開發者開發的應用所共享的鑰匙串群組標識
在ios應用中使用key-chain
1.引入框架 import Security 修改Build Setting中Capabilities支持
使用Touch ID驗證用戶
1.引入LocalAuthentication框架
2.創建LAContext類的實例
3.調用LAContext實例的canEvaluatePolicy:(LAPolicyDeviceOwnerAuthenticaitonWithBiometrics)error:方法確認Touch Id是否可用
4.Touchid可用則使用LAContext的evaluatePolicy:localizedReason:reply:方法驗證TouchID的用戶
import UIKit
import LocalAuthentication
class ViewController: UIViewController {
@IBOutlet weak var buttonCheckTouchId: UIButton!
@IBOutlet weak var buttonUseTouchId: UIButton!
override func viewDidLoad() {
super.viewDidLoad()
}
//touchId是否可用
func checkTouchIdAvailability(sender: AnyObject) {
let context = LAContext()
var error: NSError?
let isTouchIdAvailable = context.canEvaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, error: &error)
buttonUseTouchId.isEnabled = isTouchIdAvailable
//Touch ID不可用的
if isTouchIdAvailable == false {
let alertController = UIAlertController(title: "Touch Id", message: "TocuhId is not available", preferredStyle: .alert)
alertController.addAction(UIAlertAction(title: "OK", style: .default, handler: nil))
present(alertController, animated: true, completion: nil)
}
}
@IBAction func userTouchId(sender: AnyObject) {
let context = LAContext()
var error: NSError?
//localizedReason標識在應用中請求用戶提供指紋進行驗證的文本提示內容
let reason = "please authenticate with Touch id to access your private information"
context.evaluatePolicy(.deviceOwnerAuthenticationWithBiometrics, localizedReason: reason, reply: { (success: Bool, error: NSError!) in
if success{
//用戶已經通過驗證
}else{
//用戶為通過驗證
}
} as! (Bool, Error?) -> Void)
}
}
在鑰匙串中存儲數據是以鍵值對方式存儲的
kSecCalss 安全存儲字符串數據
kSecClassGenericPassword
kSecAttrService 應用bundle標識字符竄
kSecAttrAcount 存儲數據的對應鍵,可以是任意有意義的字符串
kSecValueData 該鍵的值是一個NSData實例,存放kSecAttrAccount對應的數據
OSStatus類型在xcode中Commond+ shilft + O 輸入SecBase 查找errSecSucces,可以看到OSStatus類型
func application(_ application: UIApplication, didFinishLaunchingWithOptions launchOptions: [UIApplication.LaunchOptionsKey: Any]?) -> Bool {
// Override point for customization after application launch.
return true
}
//保存到鑰匙串
func savetoKeyChain() {
let key = "Full Name"
let value = "Steve Jobs"
let valueData = value.data(using: .utf8, allowLossyConversion: false)
let service = Bundle.main.bundleIdentifier!
let secItem = [
kSecClass as NSString : kSecClassGenericPassword as NSString,
kSecAttrService as NSString : service,
kSecAttrAccount as NSString : key,
kSecValueData as NSString : valueData!
] as NSDictionary
var result:CFTypeRef?
let status = Int(SecItemAdd(secItem, &result))
switch status {
case Int(errSecSuccess):
print("Successfully stored the value")
case Int(errSecDuplicateItem):
print("this item is already saved, Cannot duplicate it")
default:
print("An error occurred with code\(status)")
}
}
//在鑰匙串中查找數據
/****查找鑰匙串h中的值
SecItemCopyMatching(CFDictionary, UnsafeMutablePointer<CFTypeRef?>?)
1.構建一個字典,天劍kSecClass鍵,設置鍵的值來標識查找項的類型。 例如:kSecClassGenericPassword
2.添加kSecAttrService鍵。取值為查找項服務的字符串,所有應用應采用相同的值,這樣任意應用寫到鑰匙串的數據,其他應用可以訪問
3.添加kSecAttrAccount鍵,取值為鑰匙串已存儲項對應的鍵
4.獲取特定屬性的值:創建修改日期,需要向字典中添加kSecReturnAttributes,並將其值設置為kCFBooleanTrue
如果設置CFDictionary鍵為 kSecReturnAttributes鍵,則返回值為nil或CFDictionaryRef隱含類型
如果為kSecReturnData添加到字典,返回類型是CDDataRef
**/
func queryFromKeyChain(){
let keyToSearchfor = "Full Name"
let service = Bundle.main.bundleIdentifier
let query = [kSecClass as NSString : kSecClassGenericPassword as NSString,
kSecAttrAccount as NSString : keyToSearchfor,
kSecAttrService as NSString : service,
kSecReturnAttributes as NSString : kCFBooleanTrue
] as NSDictionary
var valueAttributes : CFTypeRef?
let results = Int(SecItemCopyMatching(query, &valueAttributes))
if results == Int(errSecSuccess) {
let attributes = valueAttributes! as! NSDictionary
let key = attributes[kSecAttrAccount as NSString] as! String
let accessGroup = attributes[kSecAttrAccessGroup as NSString] as! String
let createDate = attributes[kSecAttrCreationDate as NSString] as! NSDate
let modifiedDate = attributes[kSecAttrModificationDate as NSString] as! NSDate
let serviceValue = attributes[kSecAttrService as NSString] as! String
}else{
print("Error happened with code:\(results)")
}
}
func queryDataFromKeyChain(){
let keyToSearchfor = "Full Name"
let service = Bundle.main.bundleIdentifier
let query = [kSecClass as NSString : kSecClassGenericPassword as NSString,
kSecAttrAccount as NSString : keyToSearchfor,
kSecAttrService as NSString : service,
kSecReturnData as NSString : kCFBooleanTrue
] as NSDictionary
var returnedData : CFTypeRef?
let results = Int(SecItemCopyMatching(query, &returnedData))
if results == Int(errSecSuccess) {
let data = returnedData! as! Data
let value = String(data: data, encoding: .utf8)
}else{
print("Error happened with code:\(results)")
}
}
func updateKeyChain() {
let keyToSearchFor = "Full Name"
let service = Bundle.main.bundleIdentifier
let query = [kSecClass as NSString:
kSecClassGenericPassword as NSString,
kSecAttrService as NSString: service,
kSecAttrAccount as NSString : keyToSearchFor,] as NSDictionary
var result: CFTypeRef?
let found = Int(SecItemCopyMatching(query, &result))
if found == Int(errSecSuccess){
let newData = "Mark tremonti".data(using: .utf8, allowLossyConversion: false)
let update = [kSecValueData as NSString: newData!,
kSecAttrComment as NSString : "my comments"] as NSDictionary
let updated = Int(SecItemUpdate(query, update))
if updated == Int(errSecSuccess){
print("Successfully updated the existing value")
readExistingValue();
} else {
print("failed to update the value. error = \(updated)")
}
}else{
print("error happened. Code=\(found)")
}
}
//更新多個值
func readExistingValue() {
}