【问题标题】:iOS app's cookies get wiped out when terminated. How to prevent this, or persist this cookie?iOS 应用程序的 cookie 在终止时会被清除。如何防止这种情况,或保留这个cookie?
【发布时间】:2012-05-27 20:13:56
【问题描述】:

我正在发送带有存储在设备端的 session-cookie 的 http 请求。问题是我想在应用程序终止时保留它。但似乎我的应用程序的所有 cookie 都被删除了。我在模拟器和设备上都试过了,它们的行为相同。

是否有任何 iOS 方法可以防止此 cookie 删除?如果没有,如何将其保存到磁盘并恢复?

为了安全起见,我打算将此 cookie 保存在 iOS 钥匙串中。而且我认为所有 NSHTTPCookie 属性都可以安全地转换为 NSString。所以我目前的想法是从 NSHTTPCookie -> NSDictionary -> String -> Save in Keychain 转换,然后返回使用获取原始cookie。问题是我不想经历转换 NSDictionary -> String 和解析 String -> NSDictionary 的麻烦。

【问题讨论】:

  • 您可以自己保存和发送 cookie。
  • 是的,但是iOS有提供这种机制吗?
  • 有点。如果你有一个 NSHTTPURLResponse,你可以通过 NSHTTPCookie 的 +cookiesWithResponseHeaderFields:forURL: 方法得到一个 NSHTTPCookies 的 NSArray。然后发送它们,您只需要自己创建 Cookie: 标头。我将在答案中发布更多详细信息。

标签: ios session-cookies


【解决方案1】:

假设你有一个 NSHTTPURLResponse,你可以像这样得到一个 cookie 数组:

NSDictionary * headers = [(NSHTTPURLResponse *)response allHeaderFields];
NSArray * cookies = [NSHTTPCookie cookiesWithResponseHeaderFields:headers forURL:response.URL];

response 是 NSHTTPURLResponse。

您将在 NSURLConnectionDelegate 的这 2 个方法中获取 NSURLResponses

- (NSURLRequest *)connection:(NSURLConnection *)connection willSendRequest:(NSURLRequest *)request redirectResponse:(NSURLResponse *)redirectResponse;
- (void)connection:(NSURLConnection *)connection didReceiveResponse:(NSURLResponse *)response;

NSHTTPCookie 有一个properties 属性,它返回一个NSDictionary,所以你可以保存它们。 然后可以使用 -initWithProperties: 使用相同的字典创建它们

要发送它们,您需要为NSURLRequest 的 Cookie 标头创建自己的字符串。 比如:

NSMutableString * cookieString = [[NSMutableString alloc] init];
for (NSHTTPCookie * cookie in myLoadedCookies){
    [cookieString appendFormat:@"%@=%@; ", cookie.name, cookie.value];
}
[request setValue:cookieString forHTTPHeaderField:@"Cookie"];
[cookieString release];

其中requestNSMutableURLRequest

您还应该确保停止 iOS 自行管理 cookie:

[request setHTTPShouldHandleCookies:NO];

【讨论】:

  • 我正在使用 Restkit 发送和接收请求,所以我自己没有直接处理 NSURLRequest。我获取 cookie 的方式是 [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies,在我的情况下,它的工作方式与您的代码相同。问题是如何将 NSHTTPCookie 保存到磁盘。我正在寻找一种更好的方法,而不是遍历每个 NSDictionary 条目并生成一个长字符串,我可以将其保存到 iOS 钥匙串(出于安全考虑),然后再次将该字符串解析回 NSDictionary 以恢复 cookie。我不想经历那些解析麻烦:(
  • 如果你可以保存一个 NSDictionarys 的 NSArray,那么解析是没有意义的。 NSArray 有一个 writeToFile 方法和一个可以使用的 initWithContentsOfFile。如果您担心安全性,请将数组加密为 NSData 对象并写入。
  • 哦,谢谢,我不知道这些集合类有 writeToFile: 方法。
【解决方案2】:

找到了一种很好的干净方法。诀窍是使用JSONKit(RestKit 附带)使用 JSON 格式在 NSString 和 NSDictionary 之间进行转换。在这里,我使用SFHFKeychainUtils 来帮助我处理钥匙串的事情。这样您就不必担心 cookie 中的每个属性以及所有的转换工作。 :)

#import "RestKit/JSONKit.h"

#define WSC_serviceName @"WSC_serviceName"
#define WSC_username    @"WSC_username"
#define WSC_cookieName  @"_your_cookie_name" // name of the session cookie

- (void)saveSessionCookieToKeyChain {
    for (NSHTTPCookie *c in [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies) {
        if ([c.name isEqualToString:WSC_cookieName]) {
            NSString *cookieString = [c.properties JSONString];
            NSLog(@"cookieString: %@",cookieString);
            NSError *saveError = nil;
            [SFHFKeychainUtils storeUsername:WSC_username
                                 andPassword:cookieString 
                              forServiceName:WSC_serviceName 
                              updateExisting:YES error:&saveError];
        }
    }
}

- (BOOL)readsSessionCookieFromKeyChain {
    NSError *readError = nil;
    NSString *jsonString = [SFHFKeychainUtils getPasswordForUsername:WSC_username
                                                      andServiceName:WSC_serviceName 
                                                               error:&readError];
    if (!jsonString) return NO;
    NSData* jsonData = [jsonString dataUsingEncoding:NSUTF8StringEncoding]; // be sure that data is in UTF8 or it won't work
    JSONDecoder* decoder = [[JSONDecoder alloc] initWithParseOptions:JKParseOptionNone];
    NSDictionary* jsonDict = (NSDictionary*)[decoder objectWithData:jsonData];
    NSLog(@"jsonDict: %@",jsonDict);

    NSHTTPCookie *cookie = [[NSHTTPCookie alloc] initWithProperties:jsonDict];
    [[NSHTTPCookieStorage sharedHTTPCookieStorage] setCookie:cookie];

    return cookie!=nil;
}

- (void)clearSessionCookieAndRemoveFromKeyChain {
    for (NSHTTPCookie *c in [NSHTTPCookieStorage sharedHTTPCookieStorage].cookies) {
        [[NSHTTPCookieStorage sharedHTTPCookieStorage] deleteCookie:c];
    }
    NSError *deleteError = nil;
    [SFHFKeychainUtils deleteItemForUsername:WSC_username 
                              andServiceName:WSC_serviceName 
                                       error:&deleteError];
}

【讨论】:

    【解决方案3】:

    =====总结=====

    好吧,我将创建另一个答案,只是为了总结保持 NSDictionary 的可能方法(当然不包含对象!)。

    最简单的方法是使用 NSDictionary 的writeToFile: 方法。这将生成一个 plist 文件。 (也可在 NSArray 中使用)如果您担心安全性,请将数组加密为 NSData 对象并写入。

    另一种方法,但不是最快的方法,是使用工具将 NSDictionary 转换为字符串格式,例如 JSON 或 XML。您可以将此字符串保存在 iOS 钥匙串中,以便以后轻松检索。 (SFHFKeychainUtils 非常适合帮助处理钥匙串)。使用钥匙串的好处是它会自动加密。

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2020-03-18
      • 1970-01-01
      • 2023-04-03
      • 1970-01-01
      • 2014-07-15
      • 2018-10-16
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多