1. 程式人生 > >iOS使用者資料安全:Keychain、Touch ID以及1Password

iOS使用者資料安全:Keychain、Touch ID以及1Password

使用登入介面來保護APP使用者資料是很好的方法--你可以使用Keychain(內嵌在iOS裡的)來確保使用者資料的安全。不過蘋果現在使用Touch ID提供了另外一層保護,該功能適用於iPhone5、iPhone6、 iPhone 6+、iPad Air2以及iPad mini 3。

如果這些都還不夠,可以嘗試iOS 8引入的擴充套件,你甚至可以使用AgileBits開發的1Password app來整合登入資訊的儲存和獲取。這一切都要感謝AgileBits團隊開發者開源了他們的擴充套件包。這樣你就可以把管理登入資訊的責任交給Keychain、TouchID或者1Password。

在這個教程中,我們將使用Keychain 來儲存和驗證登入資訊。之後,我們會學習Touch ID,最後將1Password 擴充套件整合到你的app中。

注意:Touch ID和1Password要求在真機上測試,Keychain可以在模擬器上測試。

開始

在此下載該教程的初始工程檔案。

這是一個最基本的使用Core Data儲存使用者筆記的記筆APP;storyboard中包含一個登入介面,使用者可輸入使用者名稱和密碼,這個APP的其他介面已經都關聯好了,而且可以直接使用。

編譯並執行工程,檢視APP在當前狀態下的展示情況:

iOS-Simulator-Screen-Shot-Dec-21-2014-9.21.34-PM-180x320.png

現在,點選Login按鈕會關閉當前介面並展示筆記的列表-你也可以在該介面上建立一個新的筆記。點選Logout會帶你返回到Login介面。如果這個APP處於後臺,它會馬上返回到login介面。這種方式保障了在沒有登入的情況下是看不到任何資料的。將Info.plist裡面的Application does not run in background設定為YES就可以達到這個效果。

開始之前,更改Bundle Identifier,選擇一個合適的Team。

在工程導航器中選中TouchMeIn,然後選擇TouchMeIn target。在General 標籤中更改Bundle Identifier為你自己的域名-使用反向域名構造識別符號規則-例如com.raywenderich.TouchMeIn.

然後,如下,在Team選單上選擇你的開發團隊相應的賬戶。

所有配置齊全後,開始coding吧!:]

Logging? Log In.

話不多說,開始吧!現在你要增加功能來對照使用者提供的驗證資訊和硬編碼的值。

開啟LoginViewController.swift,在managedObjectContext變數宣告的下方新增下面的常量:

1 2 let usernameKey = "batman" let passwordKey = "Hello Bruce!"

以上是僅僅是硬編碼使用者名稱和密碼,用來核對使用者提供的驗證資訊。

在loginAction(_:)下方新增以下函式:

1 2 3 4 5 6 7 func checkLogin(username: String, password: String ) -> Bool { if ((username == usernameKey) && (password == passwordKey)) { return true else { return false } }

該方法檢視使用者提供的驗證資訊與你提前定義的常量是否匹配。

接下來,將loginAction(_:) 裡的內容替換為如下內容:

1 2 3 if (checkLogin(self.usernameTextField.text, password: self.passwordTextField.text)) { self.performSegueWithIdentifier("dismissLogin", sender: self) }

該方法呼叫了checkLogin(_:password:)方法,如果驗證資訊正確則收起登入介面。

編譯並執行程式,輸入使用者名稱batman和密碼Hello Bruce!,點選Login按鈕,登入介面應該按照預期被收起。

儘管這個做法可以達到驗證效果,但是非常不安全,因為以字串形式儲存驗證資訊能被訓練有素的黑客使用正確的工具輕鬆獲取。最好的策略是,永遠不要將密碼直接儲存在app裡。

為此,你應該使用Keychain 來儲存密碼。檢視Chris Lowe的Basic Security in iOS 5--Part 1教程來學習Keychain 的實際工作原理。

下一步將Keychain封裝新增到你的APP。雖然它是用Objective-C寫的,但也要新增一個bridging header標頭檔案,以便從Swift中訪問Objective-C類。

Rapper? No. Wrapper.

下載解壓後,將KeychainWrapper.h 和 KeychainWrapper.m拖進你的工程裡,如下所示:

001.png

在彈出視窗中,選中Copy items if needed 和TouchMeIn target。

002.png

在Swift工程中新增Objective-C檔案,Xcode會為你建立一個橋接標頭檔案-點選 Yes:

003.png

這時候建立了一個名為TouchMeIn-Bridging-Header.h的橋接標頭檔案。將所有Objective-C檔案的標頭檔案新增到檔案中,以便Swift工程可以訪問得到。

想要檢查橋接標頭檔案設定是否正確,在工程導航器中選擇TouchMeIn。選中Build Settings,在搜尋欄中輸Swift Compiler,然後找到Objective-C Bridging Header欄,當前欄中包含TouchMeIn/TouchMeIn-Bridging-Header.h如下圖所示:

004.png

開啟TouchMeIn-Bridging-Header.h檔案,在檔案開頭匯入Keychain 封裝包:

1 #import "KeychainWrapper.h"

編譯並執行工程,以確保沒有任何錯誤。一切正常?很好—現在你可以在APP中發揮Keychain的優勢了。

Keychain, Meet Password. Password, Meet Keychain

想使用Keychain,必須先儲存一個使用者名稱和密碼。然後檢查使用者提供的驗證資訊和keychain裡面儲存的資訊是否匹配。

你應該追蹤使用者是否已經建立了驗證資訊,以便你可以把login按鈕的展示文字從“Create”更改為“Login”。你也應該儲存使用者名稱到user defaults當中,以便檢查驗證資訊是否建立,而不是每次都訪問keychain。

開啟LoginViewController.swift檔案然後刪掉以下內容:

let usernameKey = "batman"

let passwordKey = "Hello Bruce!"

在以上刪除掉的地方新增下面的內容:

1 2 3 4 let MyKeychainWrapper = KeychainWrapper() let createLoginButtonTag = 0 let loginButtonTag = 1 @IBOutlet weak var loginButton: UIButton!

MyKeychainWrapper保留了到Objective-C KeychainWrapper類的引用。接下來的兩個常量會用來區分Login按鈕到底是用來建立驗證資訊還是用來登入;根據前面的兩個狀態(建立或登入),LoginButton outlet用來更新login 按鈕的展示文字。

開啟Main.storyboard,然後從Login View Controller裡執行Ctrl-drag操作,拖拉到Login按鈕,如圖所示:

456.png

在彈出框裡選擇loginButton

47.png

接下來,當按鈕被輕觸時,你要處理兩種可能情況:如果使用者還沒有建立過驗證資訊時,按鈕文字應該展示“Create,否則按鈕展示“Login”。你也需要檢查輸入的驗證資訊和keychain儲存的資訊是否匹配。

開啟LoginViewController.swift,將loginAction(_:) 裡面的程式碼替換為如下內容:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 @IBAction func loginAction(sender: AnyObject) { // 1. if (usernameTextField.text == "" || passwordTextField.text == "") { var alert = UIAlertView() alert.title = "You must enter both a username and password!" alert.addButtonWithTitle("Oops!") alert.show() return; } // 2. usernameTextField.resignFirstResponder() passwordTextField.resignFirstResponder() // 3. if sender.tag == createLoginButtonTag { // 4. let hasLoginKey = NSUserDefaults.standardUserDefaults().boolForKey("hasLoginKey") if hasLoginKey == false { NSUserDefaults.standardUserDefaults().setValue(self.usernameTextField.text, forKey: "username") } // 5. MyKeychainWrapper.mySetObject(passwordTextField.text, forKey:kSecValueData) MyKeychainWrapper.writeToKeychain() NSUserDefaults.standardUserDefaults().setBool(true, forKey: "hasLoginKey") NSUserDefaults.standardUserDefaults().synchronize() loginButton.tag = loginButtonTag performSegueWithIdentifier("dismissLogin", sender: self) else if sender.tag == loginButtonTag { // 6. if checkLogin(usernameTextField.text, password: passwordTextField.text) { performSegueWithIdentifier("dismissLogin", sender: self) else { // 7. var alert = UIAlertView() alert.title = "Login Problem" alert.message = "Wrong username or password." alert.addButtonWithTitle("Foiled Again!") alert.show() } } }

上述程式碼分析:

程式碼裡發生瞭如下步驟:

  1. 如果使用者名稱或密碼為空,則彈出一個提示框並從該方法返回。

  2. 如果鍵盤可見則關閉它。

  3. 如果login 按鈕的tag是createLoginButtonTag,則繼續建立一個新的login。

  4. 接下來,從NSUserDefaults裡讀取hasLoginKey 的值,該值表明Keychain裡面是否已經儲存過了密碼。如果username非空,而且hasLoginKey 表明沒有儲存過登入資訊,則將username的值儲存到NSUserDefaults。

  5. 然後使用mySetObject和writeToKeychain把密碼的值儲存在Keychain中。之後將NSUserDefaults裡面hasLoginKey的值設定為true,用以表示密碼已經被儲存在了keychain當中了。設定login按鈕的tag值為loginButtonTag ,這樣使用者下次開啟你的APP時會自動彈出讓使用者登入的介面,而不是彈出讓使用者建立登入的介面。最後,關閉loginView。

  6. 如果使用者是登入(如loginButtonTag表明),可呼叫checkLogin(_:password:)方法來驗證使用者提供的登入資訊;如果驗證資訊是匹配的,則關閉登入介面。

  7. 如果驗證失敗,則彈出提示資訊給使用者。

注意:為什麼不直接像使用者名稱那樣把密碼直接儲存在NSUserDefaults裡面呢?因為直接儲存後果很嚴重。因為NSUserDefaults是由plist檔案儲存的。Plist檔案本質上就是一個在APP的Library資料夾下的一個XML檔案 ,它可以被任何可直接接觸到裝置的任何人讀取。另一方面,Keychain則是利用Triple Digital Encryption Standard (3DES) 來加密資料的。

接下來,用以下內容替換checkLogin(_:password:)方法的實現:

1 2 3 4 5 6 7 8 func checkLogin(username: String, password: String ) -> Bool { if password == MyKeychainWrapper.myObjectForKey("v_Data") as NSString && username == NSUserDefaults.standardUserDefaults().valueForKey("username") as? NSString { return true else { return false } }

改方法檢查了使用者名稱是否匹NSUserDefaults裡儲存的值,以及密碼是否匹配Keychain裡存的值。

現在就需要根hasLoginKey的狀態來設定正確的按鈕展示文字以及tag。

將以下內容新增到viewDidLoad()方法:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 // 1. let hasLogin = NSUserDefaults.standardUserDefaults().boolForKey("hasLoginKey") // 2. if hasLogin { loginButton.setTitle("Login", forState: UIControlState.Normal) loginButton.tag = loginButtonTag createInfoLabel.hidden = true else { loginButton.setTitle("Create", forState: UIControlState.Normal) loginButton.tag = createLoginButtonTag createInfoLabel.hidden = false } // 3. let storedUsername : NSString? = NSUserDefaults.standardUserDefaults().valueForKey("username") as? NSString usernameTextField.text = storedUsername

程式碼解釋如下:

  1. 首先利用hasLoginKey的值來檢視當前使用者是否已經儲存過登入資訊。

  2. 如果儲存過,把登入按鈕的文字設為Login,更新按鈕的tag值為loginButtonTag,並隱藏createInfoLabel--包含“Start by creating a username and password”文字。如果該使用者沒有儲存過登入資訊,則設定按鈕文字為Create,且展示createInfoLabel。

  3. 最後,把使用者名稱資訊填入NSUserDefaults裡以便使用者更方便的進行登入操作 ?

編譯並執行。輸入一個你選擇的使用者名稱和密碼,點選Create。

注意:如果你忘記了把loginButton IBOutlet關聯起來,則可能會看見“Fatal error: unexpectedly found nil while unwrapping an Optional value”。如果看見了這個錯誤資訊,則照先前步驟提示將outlet關聯起來。

現在點選Logout,然後嘗試用相同的使用者名稱和密碼進行登入-應該就能看到一串筆記列表。

點選Logout再次登入,這次使用另外的一個密碼,後點Login,你應該會看到如下的錯誤提示框:

30.png

恭喜!你已經成功利用Keychain進行身份驗證啦。下一步,挑戰Touch ID吧!

Touching You, Touching Me

注意:想要嘗試Touch ID,你必須在一個支援Touch ID的真機上執行APP。目前為止,支援的裝置有iPhone 5s/6/6+、iPad Air 2以及iPad mini 3。

在這節中,除了使用Keychain外,你還要在工程中加入Touch ID。儘管Touch ID工作時並非一定要使用Keychain ,但保守起見最好還是實現一個備用的認證方法,例如Touch ID執行失敗,或者使用者手機不支援Touch ID。

開啟 Images.xcassets.

在這裡下載該工程將使用到的圖片資源。解壓並開啟資料夾,找到Touch-icon-lg.png、[email protected][email protected], 選中這三張圖片然後拉到Images.xcassets下。對於Xcode,這三張圖片是同一張圖片,只是解析度不同而已。

022.png

開啟Main.storyboard,然後從Object Library中拖一個按鈕到Login View Controller Scene,位於標籤下方。

按照下面操作,使用Attributes Inspector來調節按鈕的屬性:

  • 將Type設定為Custom.

  • 將Title設定為空.

  • 將Image設定為Touch-icon-lg.

完成後,按鈕的屬性值應該如下圖所示:

023.png

按照如下值在Size Inspector中設定按鈕:

  • Show 設為 Frame Rectangle

  • X 設為 267

  • Y 設為 341

  • Width 設為 67

  • Height 設為 66

完成後,Size Inspector應該如下圖:

024.png

選中你建立的這個新按鈕,點選storyboard畫布下方的layout bar當中的pin按鈕,按照如下資訊設定約束條件:

025.png

  • Top Space 設為 16.5

  • Width 設為 67

  • Height 設為 67

接下來,點選align 按鈕並在Container中檢查Horizontal Center。

026.png

最後,點選Resolve Auto Layout Issues圖示,選中Selected Views\Update Frames,如下所示:

027.png

這會更新按鈕的frame以便匹配新的約束。

你的介面現在應該如下圖:

028.png

下一步,依然在Main.storyboard中,開啟 Assistant Editor,確保已經展示LoginViewController.swift。

按住Ctrl鍵把新建的按鈕關聯到LoginViewController.swift,放置在其他的屬性下方,如下圖:

030.png

在彈出框中將其命名為touchIDButton,然後點選Connect。

031.png

當裝置不支援Touch ID時,這會建立一個outlet用來隱藏這個按鈕。

現在給這個按鈕加一個action。

按住Ctrl鍵拖拽這個按鈕到 LoginViewController.swift 裡的checkLogin(_:password:)方法上方:

032.png

在彈出框裡,將Connection更改為Action,將其命名為touchIDLoginAction,然後點選Connect。

編譯並執行看是否存在錯誤。目前仍然可以選擇模擬器執行,因為還沒有加任何關於Touch ID的東西。但是下面就要開始引入了。

Adding Local Authentication

實現Touch ID就跟引入Local Authentication和呼叫一些便捷卻強大的方法一樣簡單。

以下是Local Authentication文件內容:

“Local Authentication 框架提供了基於特定安全策略的向用戶要求身份驗證的工具。”

這裡提到的特定安全策略就是使用者的生物識別資訊,也就是使用者的指紋。

開啟LoginViewController.swift,在CoreData import下加入下面的import

1 import LocalAuthentication

現在需要一個指向LAContext 類的引用,還需要一個error屬性。

將以下程式碼加入所有屬性的下方:

1 2 var error : NSError? var context = LAContext()

接下來在這個教程中,你將會用到error;context引用了一個驗證上下文環境,也就是 Local Authentication中的主要元素。

在viewDidLoad() 方法底部加入下面的程式碼:

1 2 3 4 5 touchIDButton.hidden = true if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error) { touchIDButton.hidden = false }

這裡你使用了canEvaluatePolicy(_:error:)方法來檢視當前裝置是否支 Touch ID 身份驗證。如果支援,則顯示 Touch ID 按鈕;如果不支援,則隱藏按鈕。

在模擬器上編譯執行示例工程,Touch ID按鈕是隱藏的。在支援Touch ID的真機上執行,Touch ID按鈕則會顯示出來。

使用Touch ID 

還是在LoginViewController.swift中,用以下程式碼替換touchIDLoginAction(_:)方法裡的內容:

1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 @IBAction func touchIDLoginAction(sender: AnyObject) { // 1. if context.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error) { // 2. context.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Logging in with Touch ID", reply: { (success: Bool, error: NSError! ) -> Void in // 3. dispatch_async(dispatch_get_main_queue(), { if success { self.performSegueWithIdentifier("dismissLogin", sender: self) } if error != nil { var message: NSString var showAlert: Bool // 4. switch(error.code) { case LAError.AuthenticationFailed.rawValue: message = "There was a problem verifying your identity." showAlert = true case LAError.UserCancel.rawValue: message = "You pressed cancel." showAlert = true case LAError.UserFallback.rawValue: message = "You pressed password." showAlert = true default: showAlert = true message = "Touch ID may not be configured" } var alert = UIAlertView() alert.title = "Error" alert.message = message alert.addButtonWithTitle("Darn!") if showAlert { alert.show() } } }) }) else { // 5. var alert = UIAlertView() alert.title = "Error" alert.message = "Touch ID not available" alert.addButtonWithTitle("Darn!") alert.show() } }

以下是上面程式碼的解釋:

再一次使用canEvaluatePolicy(_:error:) 來檢查當前裝置是否支Touch ID。

如果該裝置支援Touch ID, 使用 evaluatePolicy(_:localizedReason:reply:) 方法來開始驗—也就是讓使用者利用Touch ID進行身份驗證。在驗證執行完畢後,evaluatePolicy(_:localizedReason:reply:) takes一個reply block

在reply block內部, 首先處理成功的情況。預設情況下, 驗證方法在私有執行緒上執行,所以程式碼會跳到主執行緒以便更新UI。如果驗證成功,則呼叫segue關閉登入介面。

如果失敗,用switch語句把每一個可能的失敗條件列舉出來,並設定相應的失敗提示資訊展示給使用者。

如果canEvaluatePolicy(_:error:)方法失敗,則展示一個通用的提示框。實際應用中, 應該分析評估並解決返回的失敗錯誤程式碼,錯誤碼可能包含以下的資訊:

  • LAErrorTouchIDNotAvailable: 該裝置不支援Touch ID。

  • LAErrorPasscodeNotSet:Touch ID要求的passcode沒啟用。 

  • LAErrorTouchIDNotEnrolled: 沒有儲存指紋資訊。

iOS會對LAErrorPasscodeNotSet和LAErrorTouchIDNotEnrolled 做出自己相對應的警告提示框。

在真機上編譯執行,然後用Touch ID測試登入。

因為LAContext 已經處理了大多數較難的部分,所以實現Touch ID其實是個相對簡單的過程。好的地方是,你可以在一個APP裡保留keychain和Touch ID兩個驗證方法以防使用者的手機不支援Touch ID。

在這個教程的第三部分也就是最後一個部分,我們將會使用1Password 的iOS 8擴充套件來儲存並獲得登入資訊,以及其他的一些敏感的使用者資訊。

用1Password進行控制

Agilebits開發的1Password密碼控制器可以在iOS、OS X、Windows以及Android上執行。它可以把登入驗證資訊,軟體許可證和其他敏感資訊儲存在一個庫裡並且用一個PBKDF2-加密的主祕鑰進行鎖定。在這一節中,你會學到怎麼樣利用擴充套件(extension)把使用者驗證資訊儲存在1Password裡,然後學習怎樣獲取這些資訊以便驗證使用者。

注意:下面章節學習中,你需要在真機上安裝1Password。

首先,你需要加一些新的圖片,將用於1Password按鈕上。

開啟 Images.xcassets. 然後,在你先前下載的資源裡,找到下面的三個檔案:

選中所有,然後把三個當成一個整體拖入到 Images.xcassets. 然後,找到這三個檔案:

再次,選中所有,然後把三個當成一個整體拖入到 Images.xcassets.

開啟Main.storyboard,從Object Library裡面拖一個按鈕到Login View Controller Scene裡,位於的Touch ID按鈕下方。在Attributes Inspector裡,調整這個按鈕的屬性為如下值:

  • 將Type設定為Custom

  • 將Title設定為空

  • 將Image設定為onepassword-button

Attributes Inspector應該如下圖所示:

61.png

使用Size Inspector調整放置資訊和大小資訊,如下值:

  • 將X設定為287

  • 將Y設定為426

  • 將Width設定為27

  • 將Height設定為33

你可以比對下圖來檢查大小資訊和位置資訊是否設定正確:

62.png

保持按鈕仍然是被選中狀態,點選storyboard下方layout條上pin,並且設定按鈕的距離上部空間為21,寬度為27,高度為33:

63.png

接下來,點選layout條中的align,並在Container裡面勾選上Horizontal Center。

64.png

還是在Main.storyboard裡,開啟 Assistant Editor,當下會自動開啟LoginViewController.swift-如果沒有開啟,則在跳轉欄中選中這個檔案。現在按住Ctrl鍵把按鈕拖向LoginViewController.swift中的其他屬性下方,如下圖所示:

65.png

在彈出框裡把名字設定為onepasswordSigninButton,點選Connect:

66.png

這會建立一個IBOutlet,根據其功能是否可用,你將用它來更改1Password按鈕的圖片。

接下來為onepasswordSigninButton新增一個action。按Ctrl健並把該按鈕拖向LoginViewController.swift裡的checkLogin(_:password:)方法上方。

67.png

將Connection型別更改為Action。將名稱設定為canUse1Password,且將Arguments設定為Sender,點選Connect。

68.png

編譯執行。如下圖,你會看到一個新的1Password按鈕展現出來,如下所示:

69.png

一個靈活的拓展

現在介面展示出來了,你可以開始實現1Password的支援了!

如下展示的那樣,找到GitHub上的1Password 擴充套件倉庫地址,點選下載ZIP:

70.png

解壓下載下來的檔案。開啟資料夾並且把OnePasswordExtension.h和OnePasswordExtension.m檔案拖到你的工程裡,如下圖:

71.png

確保勾選Copy items if needed和TouchMeIn。

回想當初新增Objective-C 檔案到Swift工程裡時,Xcode自動提供了一個bridging header標頭檔案。鑑於最初時已經建立了這樣的一個bridging header標頭檔案,現在你可以直接將1Password的頭加入那個檔案中。

開啟TouchMeIn-Bridging-Header.h檔案然後加入下面的import:

1 #import "OnePasswordExtension.h"

開啟LoginViewController.swift然後加入下面import到檔案的頂端:

1 import Security

這僅僅簡單地匯入了1Password 擴充套件需要的Security框架。

現在將以下屬性新增至LoginViewController的頂端:

1 2 let MyOnePassword = OnePasswordExtension() var has1PasswordLogin: Bool = false

前一個屬性保留了1Password擴充套件的主類的關聯,後一個屬性追蹤了1Password記錄是否被建立過;一開始設定預設為false因為在最開始執行時肯定沒有建立過。

接下來,使用以下程式碼更新viewDidLoad()裡整個if halogen 塊裡的程式碼:

1 2 3 4 5 6 7 8 9 10 11 if hasLogin { loginButton.setTitle("Login", forState: UIControlState.Normal) loginButton.tag = loginButtonTag createInfoLabel.hidden = true onepasswordSigninButton.enabled = true else { loginButton.setTitle("Create", forState: UIControlState.Normal) loginButton.tag = createLoginButtonTag createInfoLabel.hidden = false onepasswordSigninButton.enabled = false }

這使得onepasswordSigninButton在初始使用者名稱和密碼儲存進Keychain之前是無效的。

現在你需要進入1Password擴充套件裡測試是否安裝了這個iOS app以及其是否可用,如果是就啟用1Password按鈕。

將以下程式碼加入viewDidLoad()方法:

1 2 3 4 5 6 7 8 9 10 onepasswordSigninButton.hidden = true var has1Password = NSUserDefaults.standardUserDefaults().boolForKey("has1PassLogin") if MyOnePassword.isAppExtensionAvailable() { onepasswordSigninButton.hidden = false if has1Password { onepasswordSigninButton.setImage(UIImage(named: "onepassword-button") , forState: .Normal) else { onepasswordSigninButton.setImage(UIImage(named: "onepassword-button-green") , forState: .Normal) } }

這裡預設是隱藏了onepasswordSigninButton,並且僅當擴充套件被安裝後才顯示它。接下來將NSUserDefaults裡面key has1PassLogin的值賦值給has1Password來指明1Password記錄是否被建立過。

接下來,當點1Password按鈕時,更改canUse1Password以便向console輸出一個簡單的訊息。

1 2 3 @IBAction func canUse1Password(sender: AnyObject) { println("one password") }

在已安裝1Password的模擬器和真機上編譯和執行你的APP。1Password按鈕應該在模擬器上是隱藏的,且在真機上該按鈕應該顯示為綠色。點選1Password按鈕,以下資訊將顯示在console上:

1 one password

深入1Password強大之處

1Password擴充套件裡有一些方法你可以使用:

storeLoginForURLString(_:loginDetails:passwordGenerationOptions:forViewController:sender:)方法讓你建立一些登入驗證資訊,findLoginForURLString(_:forViewController:sender:completion:)方法能讓你從1Password庫裡檢索驗證資訊。

開啟LoginViewController.swift,並新增以下新方法:

1 2 3 4 5 6 7 8 9 10 11 12 13

相關推薦

iOS使用者資料安全KeychainTouch ID以及1Password

使用登入介面來保護APP使用者資料是很好的方法--你可以使用Keychain(內嵌在iOS裡的)來確保使用者資料的安全。不過蘋果現在使用Touch ID提供了另外一層保護,該功能適用於iPhone5、iPhone6、 iPhone 6+、iPad Air2以及iPad mi

資源管理(大資料Zookeeper Yarn簡介原理

https://blog.csdn.net/wzk646795873/article/details/79583218 Zookeeper Zookeeper是一個分散式協調服務,一個leader,多個follower組成的叢集,就是為使用者的分散式應用程式提供協調服務。 Zookeep

資料基礎---《利用Python進行資料分析·第2版》第8章 資料規整聚合合併和重塑

之前自己對於numpy和pandas是要用的時候東學一點西一點,直到看到《利用Python進行資料分析·第2版》,覺得只看這一篇就夠了。非常感謝原博主的翻譯和分享。 在許多應用中,資料可能分散在許多檔案或資料庫中,儲存的形式也不利於分析。本章關注可以聚合、合併、重塑資料的方法。 首先

演算法班筆記 第九章 資料結構區間陣列矩陣和樹狀陣列

第九章 資料結構:區間、陣列、矩陣和樹狀陣列 子陣列與字首和  Subarry PrefixSum[i] = A[0] + A[1] + ... + A[i-1], PrefixSum[0] = 0; 構造花費 O(n) 時間,O(n) 空間 Sum(i to j)

《大資料時代生活工作與思維的大變革》下載

2018年11月02日 14:09:24 無人寵 @ 閱讀數:1 標籤: 程式設計 資料 區塊

第八篇2 資料規整聚合合併和重塑

在許多應⽤中,資料可能分散在許多⽂件或資料庫中,儲存的形式也不利於分析。本章關注可以聚合、合併、重塑資料的⽅法。⾸先,介紹pandas的層次化索引,它⼴泛⽤於以上操作。然後,深⼊介紹了⼀些特殊的資料操作。 一、層次化索引 層次化索引(hierarchical indexing)是pandas的⼀項重要

ch8_01 資料規整聚合合併重塑

在許多應用中,資料可能分散在許多檔案或資料庫中,儲存的形式也不利於分析。本章關注可以聚合、合併、重塑資料的方法。 import pandas as pd import numpy as np 8

IOS--UIView 視覺效果圓角陰影邊框漸變光澤

首先新增框架  QuartzCore.framework 在檔案中引入  #import <QuartzCore/QuartzCore.h> - (void)viewDidLoad {     [superviewDidLoad]; // Do any additional set

資料安全獨立釋出的Oracle嚴重 CVE-2018-3110 公告

更多資料庫諮詢精彩早知道:“資料和雲”公眾號 在 2018年8月10日,Oracle 獨立的傳送了一封"安全警告"郵件給所有的 Oracle 使用者,這封郵件的標題是:Oracle Security Alert for CVE-2018-3110。這也是今年 Ora

資料規整連線聯合與重塑

1.1分層索引 分層索引是pandas的重要特性,允許你在一個軸向上擁有多個(兩個或兩個以上)索引層級。籠統地說,分層索引提供了一種在更低維度的形式中處理更高維度資料的方式。先建立一個Series,以列表的列表(或陣列)作為索引: data=pd.Series(np.random.r

資料計算(大資料MapReduceSparkStorm概述特點原理

MapReduceMapReduce將複雜的、運行於大規模叢集上的平行計算過程高度地抽象到了兩個函式:Map和Reduce。特點:程式設計容易;分而治之策略(大規模資料集,會被切成許多獨立分片,分片由多個Map任務);計算向資料靠攏(設計理念)函式輸入輸出說明Map<k

C語言的三種整型資料型別intshort int和long int

int資料型別的位數為16位,short int資料型別的位數也是16位。而long int的位數為32位,可用來儲存比較大的整數。  short int 和 long int可以縮寫為short 和 long。               C語言中的整型資料型別int、

平臺管理(大資料HueOoizeAmbari概述

 HueHue是一個開源的Apache Hadoop UI系統,通過使用Hue我們可以在瀏覽器端的Web控制檯上與Hadoop叢集進行互動來分析處理資料,例如操作HDFS上的資料,執行MapReduce Job等等。(1) 基於檔案瀏覽器(File Browser)訪問HDF

資料結構和佇列(1)——抽象資料型別

       引子:程式設計的基本法則之一是模組化,即每個模組是一個邏輯單位,並能實現某個特定的功能。其優點有三點:一、模組化的程式,在除錯上較為容易。二、模組化程式程式設計,更容易實現多人可以同時工作。三、一個好的模組化程式把某些依賴關係只侷限在一個例程中,這樣使得修改起

iOS簡單動畫效果閃爍移動旋轉路徑組合

#define kDegreesToRadian(x) (M_PI * (x) / 180.0) #define kRadianToDegrees(radian) (radian*180.0)/(M_PI) - (void)viewDidLoad { [su

資料結構圖的遍歷

樹的遍歷 先根遍歷:樹非空,先訪問根節點,在按照從左到右的順序遍歷根節點的每一顆子樹。這個訪問順序與這棵樹對應的二叉樹的先序遍歷順序相同。 後根遍歷:樹非空,則按照從左到右的順序遍歷根節點的每一顆子樹,之後在訪問根節點。其訪問順序和這棵樹對應的二叉樹的中序遍歷順序相同。

資料結構樹結構概述

    在此文,我們將總結下資料結構中樹結構的主要知識點。1、樹的定義    樹(Tree)時n(n>=0)個結點的有限集,當n==0時稱為空樹,對於非空樹:        (1)、有且僅有一個根結點;        (2)、除去根結點,其餘結點可分為m(m>0)

分析挖掘(大資料hiveimpala Spark MLlib概述原理

hiveHive是一個構建於Hadoop頂層的資料倉庫工具,支援大規模資料儲存、分析,具有良好的可擴充套件性。某種程度上可以看作是使用者程式設計介面,本身不儲存和處理資料。依賴分散式檔案系統HDFS儲存資料,依賴分散式平行計算模型MapReduce處理資料。定義了簡單的類似S

資料結構ArrayHashMap 與 List 深入解析

當開發程式時,我們(通常)需要在記憶體中儲存資料。根據操作資料方式的不同,可能會選擇不同的資料結構。有很多常用的資料結構,如:Array、Map、Set、List、Tree、Graph 等等。(然而)為程式選取合適的資料結構可能並不容易。因此,希望這篇文章能幫助你瞭解(不同資

【精】iOS 日期操作總結NSDateNSDateFormatter

1、日期(NSDate) ///////////////////////////////////////////////////////////////////////// // //(1)NSDate 初始化 // ////////////////////////////