因此在我的应用中,当用户成功使用用户名和密码登录时,钥匙串将保存用户名和密码。钥匙串的实现来自此link。
这是我的登录实现,其中钥匙串保存用户名和密码:
func loginUser(from url: URL, with username: String, and password: String, completionHandler: @escaping (DrivetimeUserProfile?, DrivetimeAPIError.LoginError?) -> Void) {
let request = makeLoginRequest(url: url, with: username, password: password)
let task = session.dataTask(with: request) { (data, response, error) in
guard let data = data else {
completionHandler(nil, .EmptyData)
return
}
do {
let userProfile = try JSONDecoder().decode(DrivetimeUserProfile.self, from: data)
completionHandler(userProfile, nil)
self.accountName = username
self.keychainItem = KeychainPasswordItem(service: KeychainConfiguration.serviceName, account: username, accessGroup: KeychainConfiguration.accessGroup)
try self.keychainItem?.savePassword(password)
} catch {
completionHandler(nil, .CannotDecodeJson)
}
}
task.resume()
}
}
然后,在我的loginViewController
中,点击loginButton
时,它会像这样调用loginUser
:
@IBAction func onLoginButtonTapped(_ sender: Any) {
let url = URL(string: BASE_URL)!
if !isUsernameAndPasswordIsFilled() {
let alert = makeAlertDialogue(with: "Incomplete Information", description: "Please make you enter both username and password")
present(alert, animated: true, completion: nil)
return
}
client.loginUser(from: url, with: userNameTextField.text!, and: passwordTextField.text!) { [weak self] (userProfile, error) in
self?.performUIUpdate {
guard error == nil else {
self?.handleLoginError(error: error)
return
}
self?.userProfile = userProfile
self?.performSegue(withIdentifier: "mainTabBarController", sender: nil)
}
}
}
但是,当我尝试访问savedPassword时,它将检索nil
。我进行了一些调试,我确定它将保存在钥匙串中。我什至创建了一个单独的项目来向自己证明苹果的示例代码确实有效。难道就是我要从后台线程保存密码,并且正在访问loginViewController
中主线程中的钥匙串吗?
谢谢!
更新
以下是访问loginViewController
中的钥匙串的代码:
override func viewDidLoad() {
super.viewDidLoad()
navigationController?.navigationBar.prefersLargeTitles = true
print(try! client.keychainItem?.readPassword())
}
答案 0 :(得分:0)
我只是从您的链接安装示例项目,并且已经过测试工作。 我假设您正确配置KeychainPasswordItem类。 在您的代码中我看到一个用户名,您可以检查密码是否正确的用户名。
if let accountName = accountName {
do {
let passwordItem = KeychainPasswordItem(service:KeychainConfiguration.serviceName, account: accountName, accessGroup: KeychainConfiguration.accessGroup)
accountNameField.text = passwordItem.account
passwordField.text = try passwordItem.readPassword()
}
catch {
fatalError("Error reading password from keychain - \(error)")
}
}