2010-04-18 3 views
25

В моем приложении для iPhone я хочу иметь возможность повторно использовать тот же сеанс на стороне сервера, когда мое приложение перезагрузится. Сеанс на сервере идентифицируется cookie, который отправляется по каждому запросу. Когда я перезапущу приложение, этот файл cookie исчез, и я больше не могу использовать тот же сеанс.iPhone: NSHTTPCookie не сохраняется через перезагрузки приложений

Что я заметил, когда использовал NSHTTPCookieStorage, чтобы найти файл cookie, который я получил с сервера, является то, что [cookie isSessionOnly] возвращает YES. У меня создается впечатление, что именно поэтому куки-файлы не сохраняются в перезагрузках моего приложения. Что мне нужно сделать, чтобы сделать мой cookie НЕ сеансом? Какие заголовки HTTP мне нужно отправить с сервера?

ответ

41

Вы можете сохранить файл cookie, сохранив его словарь свойств, а затем восстановив его в качестве нового файла cookie перед переходом на повторное подключение.

Сохранить:

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

Нагрузка:

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]; 
} 
+1

вам нужно синхронизировать nsuserdefaults? – ninjaneer

+1

Вам нужно только синхронизировать, если вам нужно сохранить их прямо тогда. В противном случае они будут сохранены в какое-то промежуточное время позже. Вот страница документа: http://developer.apple.com/library/mac/#documentation/Cocoa/Reference/Foundation/Classes/NSUserDefaults_Class/Reference/Reference.html#//apple_ref/occ/instm/NSUserDefaults/synchronize –

2

Я считаю, что на сервере решить, будет ли cookie сеансовым, вы ничего не можете с этим поделать.

+0

Нет, это действительно клиент (приложение для iPhone), который выкидывает cookie сеанса. Сессия все еще существует на сервере. –

+3

Правильно, но сервер скажет iPhone-приложению, что cookie - только сеанс. –

+1

Да, и это через HTTP. Поэтому я ищу правильные заголовки для отправки с сервера, чтобы сообщить iPhone-приложению, что он может поддерживать файл cookie дольше. –

18

Я upvoted @ ответ TomIrving и я разработки здесь, потому что многие пользователи не будут видеть очень важное замечание, в котором он говорит:

«Вам нужно установить дату истечения срока действия, иначе cookie будет считаться сессией».

В сущности, cookie будет удалён при закрытии приложения, если в будущем cookie имеет дату истечения срока действия.

Вам не нужно хранить и восстанавливать файлы cookie в и от NSUserDefaults, если у вас есть контроль над сервером, и можете попросить его установить заголовок «Expires» на что-то в будущем. Если вы не имеете контроля над сервером или не хотите, чтобы изменить поведение вашего сервера, вы можете «трюк» ваше приложение, изменив expiresDate внутри него:

  • Получить кук вы хотите изменить из [[NSHTTPCookieStorage sharedHTTPCookieStorage] cookies]
  • Скопируйте его свойства в новый NSMutableDictionary, изменив значение "Expires" на дату в будущем.
  • Создать новое печенье из нового NSMutableDictionary с помощью: [NSHTTPCookie.cookieWithProperties:]
  • Сохранить вновь созданную с использованием куки [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie newCookie]

При повторном открытии приложения, вы заметите, что печенье не было удалены.

+2

Из подхода безопасности на стороне сервера это должен быть принятый ответ. – MandisaW

1

Swift путь

Магазин:

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

Восстановление:

static func restoreCookies() { 
    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) 
      } 
     } 
    } 
} 
4

Session только печенье истекает по своей природе. Вы можете сохранить их вручную в Keychain, если вы действительно этого хотите.Я предпочитаю Keychain сохранять в UserDefaults или архивировать, потому что файлы cookie лучше защищаются, как и пароль пользователя.

К сожалению, сохранение cookie, предназначенное только для сеансов, не очень полезно, приведенный ниже код является лишь иллюстрацией того, как хранить файлы cookie, но не может заставить сервер принимать такие файлы cookie любым способом (если только вы не можете управлять сервером).

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

СВИФТ 3

СОХРАНИТЬ:

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

GET:

let cookie: HTTPCookie = NSKeyedUnarchiver.unarchiveObject(with: UserDefaults.standard.object(forKey: Constants.SHARED_DEFAULT.COOKIE_SMS) as! Data) as! HTTPCookie 
     HTTPCookieStorage.shared.setCookie(cookie) 
Смежные вопросы