2016-07-04 2 views
0

私はREST API Webサービスにアクセスするアプリケーションを開発中です。私が最近ログアウトしてユーザーを切り替える機能を開発し始めたのを除いて、すべてがうまくいっています。私は奇妙な状況に陥りました。ログアウトした後、パスワードを入力せずにもう一度ログインをクリックすると、動作しています。私もコードをデバッグし、パスワードが空白であることを確認しましたが、認証はまだ動作しています。ここでは、コードは次のとおりです。パスワードがどこかにキャッシュされていて、クリアする必要があります

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 
    } 
} 

パスワードがされている場合、私は知りませんキャッシュされます。何か案は?

+0

コード全体を表示できますか?ボタンのActionコンセントからリクエストに移動します。 –

+0

完了。現在、ビューコントローラ全体が含まれています。ありがとう! – GED125

+0

ログオフ機能でNSUserDefaults.standardUserDefaults()。setValue( ""、forKey: "password")を呼び出してみませんか? – Emptyless

答えて

0

私の問題は、パスワードのキャッシュに関連していませんでした。私の比較的アマチュアな経験レベルのおかげで、セッションを維持しているクッキーかもしれないという事実を考えたことはありませんでした。それはまさにそれが終わったものです。私はログアウト手順中にすべてのクッキーを削除するだけで状況を解決しました。ログアウトコードに以下を追加しました。完全に動作しています。

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) 
} 
0

あなたの問題は、パスワードを処理する際のロジックの一部にあると思います。まず、func CheckUser()の場合、ユーザのデフォルト値から!logOutUserの場合はvar passwordの値を割り当てますが、このプロパティ(パスワード)はいつでもクリアされません。したがって、!logOutUserfalseの場合(常にそうであるように見えますが、どこにでも)、入力フィールドが空の場合は、そこに格納していた以前の値が使用されます。

したがって、パスワードフィールドにデータが保存されていることが原因で問題が発生した場合は、リクエストを実行した後にこれらのフィールド(usernamepassword)をクリアするだけです。より良い解決策は、直接usernameField.text値を直接渡し、完了後に値をクリアすることです。

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

私も指すしたいと思います(私はあなたがセッションを検証するためにそれを必要とする場合は、認証トークンを使用する必要があり、私は再考をお勧めしている、あなたのアプリで、ユーザーのパスワードを格納している理由はわかりませんよ)これらのフィールドにオプションを使用する必要がある場合は、ユーザーのデフォルトにアンラッピングをオプションで使用し、空のフィールドでリクエストを送信しないように検証メカニズムを追加してください。理想的にはボタンが無効になるか、無効なフィールドの

Good Luck!

EDIT

このアプローチを試してみてください。むしろ、パスワードのユーザー名とサーバーの値のクラスプロパティを使用するよりも。メソッド変数を使用して値を設定すると、メソッドが終了するとこれらの値が破棄されます。 (これはコンパイラが手元にないので、多少の構文エラーがあるかもしれないので、暗闇の中ではちょっとしたショットです。 - ノートメソッドのシグネチャ

func CheckUser(username: String, password: String, server: String){ 
let port = "8443" 
let config = NSURLSessionConfiguration.defaultSessionConfiguration() 
let 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. 
let task = 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() 
} 

次に、あなたはそうと、あなたのメソッドを呼び出すことができます。

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(usernameField.text, password: passwordField.text, server: serverNameField.text) 
} 
+0

こんにちはダニエル、私はログアウトボタンを持つ別のメニューがあります。ログアウト時に実行されるビューコントローラコードを追加しました。私はすべてをクリアしていますが、まだ動作しています。 – GED125

+0

私は、あなたがlogoffメソッドを実行するための通知を掲示していますが、このメソッドの中ではlogOutUserを設定していません。私はあなたのloginButtonアクションアウトレットの代わりのソリューションで私の答えを更新します。 –

+0

更新されたソリューションをお寄せいただきありがとうございます。午前中にチェックアウトして、4日目を祝いましょう。また、私は今すぐprepareForSegueメソッドで "logOutUser"を設定していることを指摘したいと思います。私はあなたの提案が好きです、私はそれをショットし、明日あなたに戻ってきます。 – GED125

関連する問題