iOS WebView 中的 Cookie场景IP直连的几种方法(3)-问答-阿里云开发者社区-阿里云

开发者社区> 问答> 正文

iOS WebView 中的 Cookie场景IP直连的几种方法(3)

猫饭先生 2017-10-20 11:20:38 1385
使用方法示例:
发送请求
  1. WKWebView * webView = [WKWebView new];
  2. NSMutableURLRequest * request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"http://xxx.com/login"]];
  3. NSString *value = [[HTTPDNSCookieManager sharedInstance] getRequestCookieHeaderForURL:url];
  4. [request setValue:value forHTTPHeaderField:@"Cookie"];
  5. [webView loadRequest:request];

接收处理请求:
  1.     NSURLSessionTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
  2.         if (!error) {
  3.             NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
  4.             // 解析 HTTP Response Header,存储cookie
  5.             [[HTTPDNSCookieManager sharedInstance] handleHeaderFields:[httpResponse allHeaderFields] forURL:url];
  6.         }
  7.     }];
  8.     [task resume];

通过 document.cookie 设置 Cookie 解决后续页面(同域)Ajax、iframe 请求的 Cookie 问题;
  1. WKUserContentController* userContentController = [WKUserContentController new];
  2. WKUserScript * cookieScript = [[WKUserScript alloc] initWithSource: @"document.cookie = 'skey=skeyValue';" injectionTime:WKUserScriptInjectionTimeAtDocumentStart forMainFrameOnly:NO];
  3. [userContentController addUserScript:cookieScript];


Cookie包含动态 IP 导致登陆失效问题


关于COOKIE失效的问题,假如客户端登录 session 存在 COOKIE,此时这个域名配置了多个IP,使用域名访问会读对应域名的COOKIE,使用IP访问则去读对应IP的COOKIE,假如前后两次使用同一个域名配置的不同IP访问,会导致COOKIE的登录session失效,
如果APP里面的webview页面需要用到系统COOKIE存的登录session,之前APP所有本地网络请求使用域名访问,是可以共用COOKIE的登录session的,但现在本地网络请求使用httpdns后改用IP访问,导致还使用域名访问的webview读不到系统COOKIE存的登录session了(系统COOKIE对应IP了)。IP直连后,服务端返回Cookie包含动态 IP 导致登陆失效。
使用IP访问后,服务端返回的cookie也是IP。导致可能使用对应的域名访问,无法使用本地cookie,或者使用隶属于同一个域名的不同IP去访问,cookie也对不上,导致登陆失效,是吧。
我这边的思路是这样的,
  • 应该得干预cookie的存储,基于域名。
  • 根源上,api域名返回单IP

第二种思路将失去DNS调度特性,故不考虑。第一种思路更为可行。

基于 iOS11 API WKHTTPCookieStore 来解决 WKWebView 的 Cookie 管理问题


当每次服务端返回cookie后,在存储前都进行下改造,使用域名替换下IP。之后虽然每次网络请求都是使用IP访问,但是host我们都手动改为了域名,这样本地存储的 cookie 也就能对得上了。
代码演示:
在网络请求成功后,或者加载网页成功后,主动将本地的 domain 字段为 IP 的 Cookie 替换 IP 为 host 域名地址。
  1. - (void)updateWKHTTPCookieStoreDomainFromIP:(NSString *)IP toHost:(NSString *)host {
  2.     WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
  3.     [cookieStroe getAllCookies:^(NSArray<NSHTTPCookie *> * _Nonnull cookies) {
  4.         [[cookies copy] enumerateObjectsUsingBlock:^(NSHTTPCookie * _Nonnull cookie, NSUInteger idx, BOOL * _Nonnull stop) {
  5.             if ([cookie.domain isEqualToString:IP]) {
  6.                 NSMutableDictionary<NSHTTPCookiePropertyKey, id> *dict = [NSMutableDictionary dictionaryWithDictionary:cookie.properties];
  7.                 dict[NSHTTPCookieDomain] = host;
  8.                 NSHTTPCookie *newCookie = [NSHTTPCookie cookieWithProperties:[dict copy]];
  9.                 [cookieStroe setCookie:newCookie completionHandler:^{
  10.                     [self logCookies];
  11.                     [cookieStroe deleteCookie:cookie
  12.                             completionHandler:^{
  13.                                 [self logCookies];
  14.                             }];
  15.                 }];
  16.             }
  17.         }];
  18.     }];
  19. }

iOS11中也提供了对应的 API 供我们来处理替换 Cookie 的时机,那就是下面的API:
  1. @protocol WKHTTPCookieStoreObserver <NSObject>
  2. @optional
  3. - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore;
  4. @end
  1. //WKHTTPCookieStore
  2. /*! @abstract Adds a WKHTTPCookieStoreObserver object with the cookie store.
  3. @param observer The observer object to add.
  4. @discussion The observer is not retained by the receiver. It is your responsibility
  5. to unregister the observer before it becomes invalid.
  6. */
  7. - (void)addObserver:(id<WKHTTPCookieStoreObserver>)observer;
  8. /*! @abstract Removes a WKHTTPCookieStoreObserver object from the cookie store.
  9. @param observer The observer to remove.
  10. */
  11. - (void)removeObserver:(id<WKHTTPCookieStoreObserver>)observer;

用法如下:
  1. @interface WebViewController ()<WKHTTPCookieStoreObserver>
  2. - (void)viewDidLoad {
  3.     [super viewDidLoad];
  4.     [NSURLProtocol registerClass:[WebViewURLProtocol class]];
  5.     NSHTTPCookieStorage *cookieStorage = [NSHTTPCookieStorage sharedHTTPCookieStorage];
  6.     [cookieStorage setCookieAcceptPolicy:NSHTTPCookieAcceptPolicyAlways];
  7.     WKHTTPCookieStore *cookieStroe = self.webView.configuration.websiteDataStore.httpCookieStore;
  8.     [cookieStroe addObserver:self];
  9.     [self.view addSubview:self.webView];
  10.     //... ...
  11. }
  12. #pragma mark -
  13. #pragma mark - WKHTTPCookieStoreObserver Delegate Method
  14. - (void)cookiesDidChangeInCookieStore:(WKHTTPCookieStore *)cookieStore {
  15.     [self updateWKHTTPCookieStoreDomainFromIP:CYLIP toHost:CYLHOST];
  16. }

-updateWKHTTPCookieStoreDomainFromIP 方法的实现,在上文已经给出。
这个方案需要客户端维护一个IP —> HOST的映射关系,需要能从 IP 反向查找到 HOST,这个维护成本还时挺高的。下面介绍下,更通用的方法,也是iOS11 之前的处理方法:

存储 网络协议 前端开发 API 调度 Android开发 iOS开发
分享到
取消 提交回答
全部回答(0)
开发与运维
使用钉钉扫一扫加入圈子
+ 订阅

集结各类场景实战经验,助你开发运维畅行无忧

推荐文章
相似问题