iPhone: NSHTTPCookie no se guarda en reinicios de la aplicación

En mi aplicación de iPhone, quiero poder reutilizar la misma sesión del lado del servidor cuando se reinicie mi aplicación. Una sesión en el servidor se identifica mediante una cookie, que se envía en cada solicitud. Cuando reinicio la aplicación, esa cookie se va y ya no puedo usar la misma sesión.

Lo que noté cuando utilicé NSHTTPCookieStorage para buscar la cookie que obtuve del servidor, es que [cookie isSessionOnly] devuelve YES . Me da la impresión de que es por eso que las cookies no se guardan en los reinicios de mi aplicación. ¿Qué tendría que hacer para que mi cookie NO sea solo una sesión? ¿Qué encabezados HTTP debo enviar desde el servidor?

Puede guardar la cookie guardando su diccionario de propiedades y luego restaurarla como una nueva cookie antes de volver a conectarse.

Salvar:

 NSArray* allCookies = [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookiesForURL:[NSURL URLWithString:URL]]; for (NSHTTPCookie *cookie in allCookies) { if ([cookie.name isEqualToString:MY_COOKIE]) { NSMutableDictionary* cookieDictionary = [NSMutableDictionary dictionaryWithDictionary:[[NSUserDefaults standardUserDefaults] dictionaryForKey:PREF_KEY]]; [cookieDictionary setValue:cookie.properties forKey:URL]; [[NSUserDefaults standardUserDefaults] setObject:cookieDictionary forKey:PREF_KEY]; } } 

Carga:

 NSDictionary* cookieDictionary = [[NSUserDefaults standardUserDefaults] dictionaryForKey:PREF_KEY]; NSDictionary* cookieProperties = [cookieDictionary valueForKey:URL]; if (cookieProperties != nil) { NSHTTPCookie* cookie = [NSHTTPCookie cookieWithProperties:cookieProperties]; NSArray* cookieArray = [NSArray arrayWithObject:cookie]; [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookies:cookieArray forURL:[NSURL URLWithString:URL] mainDocumentURL:nil]; } 

He votado a favor la respuesta de @ItIrving y estoy elaborando aquí porque muchos usuarios no verán el comentario muy importante en el que dice:

“Debe establecer una fecha de caducidad; de lo contrario, se supone que la cookie es solo una sesión”.

Básicamente, la cookie se eliminará cuando cierre su aplicación A MENOS QUE la cookie tenga una fecha de vencimiento en el futuro.

No necesita almacenar y restaurar las cookies en y desde NSUserDefaults si tiene control sobre el servidor y puede pedirle que configure el encabezado “Caduca” para algo en el futuro. Si no tiene control sobre el servidor o no desea anular el comportamiento de su servidor, puede ‘engañar’ su aplicación cambiando el expiresDate de expiresDate dentro de este:

  • Obtenga la cookie que desea modificar de las cookies [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]
  • Copie sus propiedades a un nuevo NSMutableDictionary , cambiando el valor "Expires" a una fecha en el futuro.
  • Cree una nueva cookie desde el nuevo NSMutableDictionary usando: [NSHTTPCookie.cookieWithProperties:]
  • Guarde la cookie recién creada usando [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie newCookie]

Cuando vuelvas a abrir tu aplicación, verás que la cookie no se ha eliminado.

Las cookies de solo sesión caducarán por su naturaleza. Puede almacenarlos manualmente en Keychain si realmente lo desea. Prefiero que Keychain se guarde en UserDefaults o en el archivo, porque las cookies están mejor aseguradas, al igual que la contraseña del usuario.

Lamentablemente, guardar cookies de sesión solo no es muy útil, el siguiente código es solo una ilustración de cómo almacenar cookies, pero no puede obligar al servidor a aceptar dichas cookies de ninguna manera (a menos que pueda controlar el servidor).

Swift 2.2

 // Saving into Keychain if let cookies = NSHTTPCookieStorage.sharedHTTPCookieStorage().cookies { let cookiesData: NSData = NSKeyedArchiver.archivedDataWithRootObject(cookies) let userAccount = "some unique string to identify the item in Keychain, in my case I use username" let domain = "some other string you can use in combination with userAccount to identify the item" let keychainQuery: [NSString: NSObject] = [ kSecClass: kSecClassGenericPassword, kSecAttrAccount: userAccount + "cookies", kSecAttrService: domain, kSecValueData: cookiesData] SecItemDelete(keychainQuery as CFDictionaryRef) //Trying to delete the item from Keychaing just in case it already exists there let status: OSStatus = SecItemAdd(keychainQuery as CFDictionaryRef, nil) if (status == errSecSuccess) { print("Cookies succesfully saved into Keychain") } } // Getting from Keychain let userAccount = "some unique string to identify the item in Keychain, in my case I use username" let domain = "some other string you can use in combination with userAccount to identify the item" let keychainQueryForCookies: [NSString: NSObject] = [ kSecClass: kSecClassGenericPassword, kSecAttrService: domain, // we use JIRA URL as service string for Keychain kSecAttrAccount: userAccount + "cookies", kSecReturnData: kCFBooleanTrue, kSecMatchLimit: kSecMatchLimitOne] var rawResultForCookies: AnyObject? let status: OSStatus = SecItemCopyMatching(keychainQueryForCookies, &rawResultForCookies) if (status == errSecSuccess) { let retrievedData = rawResultForCookies as? NSData if let unwrappedData = retrievedData { if let cookies = NSKeyedUnarchiver.unarchiveObjectWithData(unwrappedData) as? [NSHTTPCookie] { for aCookie in cookies { NSHTTPCookieStorage.sharedHTTPCookieStorage().setCookie(aCookie) } } } } 

Creo que depende del servidor decidir si la cookie es solo de sesión o no, no se puede hacer nada al respecto.

Manera rápida

Almacenar:

 static func storeCookies() { let cookiesStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage() let userDefaults = NSUserDefaults.standardUserDefaults() let serverBaseUrl = "http://yourserverurl.com" var cookieDict = [String : AnyObject]() for cookie in cookiesStorage.cookiesForURL(NSURL(string: serverBaseUrl)!)! { cookieDict[cookie.name] = cookie.properties } userDefaults.setObject(cookieDict, forKey: cookiesKey) } 

Restaurar:

 static func restreCookies() { let cookiesStorage = NSHTTPCookieStorage.sharedHTTPCookieStorage() let userDefaults = NSUserDefaults.standardUserDefaults() if let cookieDictionary = userDefaults.dictionaryForKey(cookiesKey) { for (cookieName, cookieProperties) in cookieDictionary { if let cookie = NSHTTPCookie(properties: cookieProperties as! [String : AnyObject] ) { cookiesStorage.setCookie(cookie) } } } } 

SWIFT 3

SALVAR:

 if let httpResponse = response as? HTTPURLResponse, let fields = httpResponse.allHeaderFields as? [String : String] { let cookies = HTTPCookie.cookies(withResponseHeaderFields: fields, for: response.url!) HTTPCookieStorage.shared.setCookies(cookies, for: response.url!, mainDocumentURL: nil) for cookie in cookies { if cookie.name == cookieName{ if cookieName == Constants.WS.COOKIES.COOKIE_SMS { UserDefaults.standard.set(NSKeyedArchiver.archivedData(withRootObject: cookie), forKey: Constants.SHARED_DEFAULT.COOKIE_SMS) UserDefaults.standard.synchronize() } return cookie.value } } } 

OBTENER:

 let cookie: HTTPCookie = NSKeyedUnarchiver.unarchiveObject(with: UserDefaults.standard.object(forKey: Constants.SHARED_DEFAULT.COOKIE_SMS) as! Data) as! HTTPCookie HTTPCookieStorage.shared.setCookie(cookie)