密码正在某处缓存,需要清除它

时间:2016-07-04 21:58:22

标签: swift

我正在开发一个访问REST API Webservice的应用程序。一切都很好,除了我最近开始着手注销和切换用户的能力,我遇到了一个奇怪的情况。如果我退出,然后再次单击登录而不输入密码,它就可以正常工作。我甚至调试了代码并看到密码为空,但验证仍然有效。这是代码:

import UIKit
import LocalAuthentication

var userName = String()
var password = String()
var server = String()
var port = String()
var myUser = User()
var myExtensions = [ExtensionListItem]()
var myDevices = [Device]()

class LoginViewController: UIViewController, NSURLSessionDelegate, UITextFieldDelegate {

let authContext: LAContext = LAContext()

var logOutUser = Bool()

@IBOutlet weak var activityIndicator: UIActivityIndicatorView!
@IBOutlet weak var serverNameField: UITextField!
@IBOutlet weak var usernameField: UITextField!
@IBOutlet weak var passwordField: UITextField!
@IBOutlet var loginEnable: UIButton!
var userPasswordString = NSString()
let userRequest = NSMutableURLRequest()
var userSession = NSURLSession()

override func viewDidLoad() {
    super.viewDidLoad()
    NSNotificationCenter.defaultCenter().addObserver(self, selector: #selector(logoff), name: "logoff", object: nil)
    if logOutUser {
        NSUserDefaults.standardUserDefaults().setValue("", forKey: "password")
        NSURLCache.sharedURLCache().removeAllCachedResponses()
        userPasswordString = NSString()
    }
    //Determine if the user has a stored Username and populate the usernameField if possible
    if NSUserDefaults.standardUserDefaults().objectForKey("userName") != nil{
        usernameField.text = NSUserDefaults.standardUserDefaults().objectForKey("userName") as? String}
    //Determine if the user has a stored ServerName and populate the serverNameField if possible.
    if NSUserDefaults.standardUserDefaults().objectForKey("serverName") != nil{
        serverNameField.text = NSUserDefaults.standardUserDefaults().objectForKey("serverName") as? String}
    //Determin if the user has requested to use Touch ID
    if (NSUserDefaults.standardUserDefaults().objectForKey("useTouchID") != nil) {
        if NSUserDefaults.standardUserDefaults().valueForKey("useTouchID") as! Bool == true && CheckTouchIDCapable(){
            //Trigger Touch ID
            usernameField.enabled = false
            passwordField.enabled = false
            serverNameField.enabled = false
            activityIndicator.startAnimating()
            TouchIDCall()
        }
    }
    // Do any additional setup after loading the view.
}

func logoff(){
    NSURLCache.sharedURLCache().removeAllCachedResponses()
    userSession.invalidateAndCancel()
}



override func didReceiveMemoryWarning() {
    super.didReceiveMemoryWarning()
    NSURLCache.sharedURLCache().removeAllCachedResponses()
    // Dispose of any resources that can be recreated.
}

@IBAction func loginButton(sender: AnyObject) {

    NSUserDefaults.standardUserDefaults().setObject(usernameField.text, forKey: "userName")
    NSUserDefaults.standardUserDefaults().setObject(passwordField.text, forKey: "password")
    NSUserDefaults.standardUserDefaults().setObject(serverNameField.text, forKey: "serverName")

    if NSUserDefaults.standardUserDefaults().valueForKey("touchIDPreferenceSet") == nil  && CheckTouchIDCapable() {
        DisplayTouchIDQuestion("Use Touch ID?", message: "Would you like to use touch ID to login?")
    }else{
        usernameField.enabled = false
        passwordField.enabled = false
        serverNameField.enabled = false
        activityIndicator.startAnimating()
        CheckUser()
    }
    print("Password: \(password)")
    print("Stored Password: \(NSUserDefaults.standardUserDefaults().valueForKey("password"))")
    print("?? \(NSUserDefaults.standardUserDefaults().objectForKey("password"))")

}

func CheckUser(){


    userName = (NSUserDefaults.standardUserDefaults().objectForKey("userName") as? String)!
    if !logOutUser{
        password = (NSUserDefaults.standardUserDefaults().objectForKey("password") as? String)!
    }
    server = (NSUserDefaults.standardUserDefaults().objectForKey("serverName") as? String)!
    port = "8443"
    // set up the base64-encoded credentials
    let config = NSURLSessionConfiguration.defaultSessionConfiguration()
    userPasswordString = NSString(format: "%@:%@", userName, password)
    let userPasswordData = userPasswordString.dataUsingEncoding(NSUTF8StringEncoding)
    let base64EncodedCredential = userPasswordData!.base64EncodedStringWithOptions(NSDataBase64EncodingOptions.Encoding64CharacterLineLength)
    let authString = "Basic \(base64EncodedCredential)"
    config.HTTPAdditionalHeaders?.removeAll()
    config.HTTPAdditionalHeaders = ["Authorization" : authString]
    config.timeoutIntervalForRequest = 10.0


    // create the user request
    let userUrlString = NSString(format: "https://%@:%@/webserver/user/%@", server, port, userName)
    let userUrl = NSURL(string: userUrlString as String)
    userRequest.cachePolicy = .ReloadIgnoringLocalAndRemoteCacheData
    userRequest.URL = userUrl!
    userRequest.HTTPMethod = "GET"
    userRequest.setValue("Basic \(base64EncodedCredential)", forHTTPHeaderField: "Authorization")
    userSession = NSURLSession(configuration: config, delegate: self, delegateQueue:NSOperationQueue.mainQueue())

    //Send User Request to the server and populate labels with response.
    _ = userSession.dataTaskWithRequest(userRequest) { (data, response, error) in
        dispatch_async(dispatch_get_main_queue(), { () -> Void in

            if error?.code != nil{
                print("ERROR: \(error!.localizedDescription)")
                self.DisplayAlert("Error", message: error!.localizedDescription)
            }else{
                _ = NSString (data: data!, encoding: NSUTF8StringEncoding)
                let dataString = NSString(data: data!, encoding: NSUTF8StringEncoding)
                let accessDenied = Bool(dataString?.rangeOfString("HTTP Status 403").location != NSNotFound)
                let authFailure = Bool(dataString?.rangeOfString("HTTP Status 401").location != NSNotFound)

                if (authFailure || accessDenied) {
                    print("\(NSDate()): Unsuccessful Password Authentication Attempt for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
                    self.DisplayAlert("Access Denied", message: "Please Verify Your Credentials")
                }else{
                    print("\(NSDate()): Successful Password Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
                    self.performSegueWithIdentifier("authenticated", sender: self)
                }
            }
        })
    }.resume()
}

func URLSession(session: NSURLSession, didReceiveChallenge challenge: NSURLAuthenticationChallenge, completionHandler: (NSURLSessionAuthChallengeDisposition, NSURLCredential?) -> Void) {
    completionHandler(NSURLSessionAuthChallengeDisposition.UseCredential, NSURLCredential(forTrust: challenge.protectionSpace.serverTrust!))
}

override func prefersStatusBarHidden() -> Bool {
    return true
}

// MARK: - Keyboard Functions

override func touchesBegan(touches: Set<UITouch>, withEvent event: UIEvent?) {
    self.view.endEditing(true)
}

func textFieldShouldReturn(textField: UITextField) -> Bool {
    textField.resignFirstResponder()
    if textField == passwordField  && usernameField.text != "" && serverNameField.text != ""{
        loginButton(self)
    }
    return true
}

func ReEnableLogin(){

    self.activityIndicator.hidesWhenStopped = true
    self.activityIndicator.stopAnimating()
    self.usernameField.enabled = true
    self.passwordField.enabled = true
    self.serverNameField.enabled = true
}

func DisplayAlert(title: String, message: String){

    let alertController = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    alertController.addAction(UIAlertAction(title: "Dismiss", style: UIAlertActionStyle.Default, handler: nil))
    self.presentViewController(alertController, animated: true, completion: nil)
    self.ReEnableLogin()

}

func DisplayTouchIDQuestion(title: String, message: String){

    let alertControllerQuestion = UIAlertController(title: title, message: message, preferredStyle: UIAlertControllerStyle.Alert)
    alertControllerQuestion.addAction(UIAlertAction(title: "Yes", style: UIAlertActionStyle.Default, handler: { (action:UIAlertAction) in
        NSUserDefaults.standardUserDefaults().setValue(true, forKey: "useTouchID")
        NSUserDefaults.standardUserDefaults().setValue(true, forKey: "touchIDPreferenceSet")
        NSUserDefaults.standardUserDefaults().setValue(self.passwordField.text, forKey: "touchIDCachedCredential")
        self.CheckUser()
    }))
    alertControllerQuestion.addAction(UIAlertAction(title: "No", style: UIAlertActionStyle.Default, handler: { (action:UIAlertAction) in
        NSUserDefaults.standardUserDefaults().setValue(false, forKey: "useTouchID")
        NSUserDefaults.standardUserDefaults().setValue(true, forKey: "touchIDPreferenceSet")
        self.CheckUser()
    }))
    self.presentViewController(alertControllerQuestion, animated: true, completion: nil)
}

func CheckTouchIDCapable()-> Bool {
    var error: NSError?
    var touchEnabledDevice: Bool = false
    if authContext.canEvaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, error: &error){
        touchEnabledDevice = true
    }
    return touchEnabledDevice
}

func TouchIDCall(){

    authContext.evaluatePolicy(LAPolicy.DeviceOwnerAuthenticationWithBiometrics, localizedReason: "Place your finger on the Home button to log into Collaboration User Tools", reply: { (wasSuccessful, error) in
            if wasSuccessful{
                print("\(NSDate()): Successful Biometric Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
                NSUserDefaults.standardUserDefaults().setValue(NSUserDefaults.standardUserDefaults().valueForKey("touchIDCachedCredential"), forKey: "password")
                self.CheckUser()

            }else{
                print("\(NSDate()): Error: \(error!.code)")
                print("\(NSDate()): Unsuccessful Biometric Authentication for user: \(NSUserDefaults.standardUserDefaults().valueForKey("userName")!)")
                let qualityOfServiceClass = QOS_CLASS_USER_INTERACTIVE
                let backgroundQueue = dispatch_get_global_queue(qualityOfServiceClass, 0)
                dispatch_async(backgroundQueue, { 
                    dispatch_async(dispatch_get_main_queue(), { () -> Void in
                        self.activityIndicator.stopAnimating()
                    })
                })
                self.ReEnableLogin()
            }
        })

}





}

我试过了:

NSURLCache.sharedURLCache().removeAllCachedResponses()
userSession.invalidatedAndCancel()

注销表视图控制器调用此方法:

override func tableView(tableView: UITableView, didSelectRowAtIndexPath indexPath: NSIndexPath) {
    switch indexPath.row{
    case 0:
        myUser = User()
        myExtensions.removeAll()
        myDevices.removeAll()
        NSUserDefaults.standardUserDefaults().setObject("", forKey: "password")
        userName = ""
        password = ""
        NSURLCache.sharedURLCache().removeAllCachedResponses()
        NSNotificationCenter.defaultCenter().postNotificationName("logoff", object: nil)
        performSegueWithIdentifier("logout", sender: self)
    default:
        break
    }
}

我不知道密码的缓存位置。有什么想法吗?

2 个答案:

答案 0 :(得分:0)

我认为您的问题在于处理密码时的部分逻辑。首先,在您的mylib.h中,如果您的用户默认值为mylib.c,则指定func CheckUser()的值,但此属性(密码)在任何时候都不会被清除,因此如果var password } !logOutUser(看起来总是如此,因为它没有在任何地方设置),并且您的输入字段为空,然后它将使用您在那里存储的先前值。

因此,如果我是正确的,并且罪魁祸首是密码字段存储其数据,那么快速,肮脏的修复就是在您之后清除这些字段(!logOutUserfalse)执行你的请求。更好的解决方法是直接直接传递username值并在完成后清除它。 (我不确定为什么要在用户的应用中存储用户密码,我建议您重新考虑,如果您需要验证会话,则应使用身份验证令牌)

password

我还想指出你应该为这些字段使用选项,你应该为你的用户默认使用可选的展开,还要添加一个验证机制,这样你就不会提交带有空字段的请求,理想情况是你的按钮将被禁用或您将提醒您的用户无效字段。

祝你好运!

修改

尝试这种方法:而不是使用类属性作为密码用户名和服务器的值。使用方法变量来设置值,这样这些值将在方法终止时被处理掉。 (这是一个在黑暗中的镜头,因为我手头没有编译器,所以可能会有一些小的语法错误)。 - 请注意方法签名

usernameField.text

然后你可以这样调用你的方法:

// set up the base64-encoded credentials
let config = NSURLSessionConfiguration.defaultSessionConfiguration()
userPasswordString = NSString(format: "%@:%@", userName, password)
userName = ""
password = ""

答案 1 :(得分:0)

我的问题从未与密码缓存有关。很可能是由于我相对业余的经验水平,我从未考虑过这可能是COOKIES保持会话的事实。这正是它最终的结果。我只是通过在注销过程中删除所有cookie来解决这个问题。我将以下内容添加到我的注销代码中,并且它运行良好。

print("\(NSDate()): Logout Requested, Deleting Cookies")
let cookieStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage()
let cookies = cookieStorage.cookies! as [NSHTTPCookie]
print("\(NSDate()): Cookie count: \(cookies.count)")
for cookie in cookies{
   print("\(NSDate()): Deleting Cookie name: \(cookie.name) value: \(cookie.value)")
   NSHTTPCookieStorage.sharedHTTPCookieStorage().deleteCookie(cookie)
}