【问题标题】:NSURLSession with Token Authentication带有令牌认证的 NSURLSession
【发布时间】:2014-01-04 11:21:04
【问题描述】:

我的iOS 项目中有以下代码,我想转换为使用NSURLSession 而不是NSURLConnection。我正在查询一个使用基于令牌的HTTP Authentication 方案的REST API,但我找不到如何执行此操作的示例。

NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:url]];

NSString *username = [[NSUserDefaults standardUserDefaults] stringForKey:@"Username"];

NSString *token = //GET THE TOKEN FROM THE KEYCHAIN


NSString *authValue = [NSString stringWithFormat:@"Token %@",token];
[request setValue:authValue forHTTPHeaderField:@"Authorization"];


if ([NSURLConnection canHandleRequest:request]){
    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];
    [NSURLConnection sendAsynchronousRequest:request queue:self.fetchQueue
                           completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) {

                               if (!connectionError) {
                                   NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
                                   if (httpResponse.statusCode == 200){
                                       NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragments error:nil];

                                       //Process the data
                                   }
                               }

                           }];
}

【问题讨论】:

  • 您使用什么请求方法,GET 或 POST 发送身份验证数据?

标签: ios objective-c ios7 nsurlsession


【解决方案1】:

你可以使用 NSURLSession 重写它,如下所示

    [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:YES];

    NSString *token ; //GET THE TOKEN FROM THE KEYCHAIN

    NSString *authValue = [NSString stringWithFormat:@"Token %@",token];

    //Configure your session with common header fields like authorization etc
    NSURLSessionConfiguration *sessionConfiguration = [NSURLSessionConfiguration defaultSessionConfiguration];
    sessionConfiguration.HTTPAdditionalHeaders = @{@"Authorization": authValue};

    NSURLSession *session = [NSURLSession sessionWithConfiguration:sessionConfiguration];

    NSString *url;
    NSURLRequest *request = [NSURLRequest requestWithURL:[NSURL URLWithString:url]];

    NSURLSessionDataTask *task = [session dataTaskWithRequest:request completionHandler:^(NSData *data, NSURLResponse *response, NSError *error) {
        [[UIApplication sharedApplication] setNetworkActivityIndicatorVisible:NO];
        if (!error) {
            NSHTTPURLResponse *httpResponse = (NSHTTPURLResponse *)response;
            if (httpResponse.statusCode == 200){
                NSDictionary *jsonData = [NSJSONSerialization JSONObjectWithData:data options:NSJSONReadingMutableContainers|NSJSONReadingAllowFragments error:nil];

                //Process the data
            }
        }

    }];
    [task resume];

【讨论】:

  • NSMutableURLRequest 的文档说:IMPORTANT The NSURLConnection class and NSURLSession classes are designed to handle various aspects of the HTTP protocol for you. As a result, you should not modify the following headers: Authorization, ...(参见:doc)。但是如果没有 [request setValue: ...] 那么怎么做呢?
  • @PaulSpieker 您可以为常见的 HTTP 标头字段配置会话。我已经更新了我的答案。
  • NSURLSessionConfiguration 的文档也说了同样的话:An NSURLSession object is designed to handle various aspects of the HTTP protocol for you. As a result, you should not modify the following headers: Authorization, ... (doc)。你的方法安全吗?
  • 我和@JacobDam 有同样的问题。我应该将 OAuth 2.0 身份验证标头 (Autorization: Bearer (token)) 传递给服务。我想我会这样做,如果它有效,请忽略 Apple 文档中的警告......
  • ...好吧,我的请求成功了,我在响应正文中得到了我期望的所有数据。也许 API 有一种推荐的、更合适的方式将身份验证标头信息(即令牌)传递给 NSURLSession/NSURLConnection,而不是直接弄乱标头?
【解决方案2】:

这是在 Swift 中,但逻辑是一样的:

    let sessionConfig = NSURLSessionConfiguration.defaultSessionConfiguration()
    let url  = NSURL(string: "some url")

    let request = NSMutableURLRequest(URL: url!)
    request.setValue("value", forHTTPHeaderField: "header field")

    let urlSession = NSURLSession(configuration: sessionConfig, delegate: self, delegateQueue: NSOperationQueue.mainQueue())


    let dataTask = urlSession.dataTaskWithRequest(request) { (data: NSData?, response: NSURLResponse?, error: NSError?) -> Void in
    }

    dataTask.resume()

【讨论】:

    【解决方案3】:

    在您的 URLSession 配置中或直接在您的请求中设置 Authorization 标头。

    请注意,Apple 表示您“不应”尝试modify the Authorization header in your URLSession configuration:

    URLSession 对象旨在为您处理 HTTP 协议的各个方面。因此,您不应修改以下标头:

    • 授权

    • ...

    但是,这是可能的。如果您想这样做,请确保在创建 URLSession 之前 设置标头配置。无法修改现有 URLSession 的标头。

    这是一个展示不同场景的 Swift Playground:

    import Foundation
    
    // 1: Wrong -- mutating existing config for existing URLSession is no-op
    
    var session = URLSession.shared
    session.configuration.httpAdditionalHeaders = ["Authorization": "123"]
    
    let url = URL(string: "https://postman-echo.com/get")!
    
    session.dataTask(with: url) { (data, resp, err) in
        if let data = data {
            let str = String(bytes: data, encoding: .utf8)!
            let _ = str
        }
    }.resume() // no authorization header
    
    // 2: Setting headers on an individual request works fine.
    
    var request = URLRequest(url: url)
    request.addValue("456", forHTTPHeaderField: "Authorization")
    session.dataTask(with: request) { (data, resp, err) in
        if let data = data {
            let str = String(bytes: data, encoding: .utf8)!
            let _ = str
        }
    }.resume() // "headers": { "authorization": "456" }
    
    // 3: You can set headers on a new URLSession & configuration
    
    var conf = URLSessionConfiguration.default
    conf.httpAdditionalHeaders = [
        "Authorization": "789"
    ]
    session = URLSession(configuration: conf)
    
    session.dataTask(with: url) { (data, resp, err) in
        if let data = data {
            let str = String(bytes: data, encoding: .utf8)!
            let _ = str
        }
    }.resume() // "headers": { "authorization": "789" }
    

    【讨论】:

    • 第一个示例不起作用,因为在将 URLSessionConfiguration 添加到 URLSession 之后对其进行变异没有任何效果。在将 httpAdditionalHeaders 添加到 URLSession 之前设置它应该可以工作。
    • 嗯,这个细节会为我省去很多麻烦和测试。 :) 谢谢@JonShier 我更新了我的帖子以反映这一点。
    猜你喜欢
    • 2018-04-05
    • 2018-01-29
    • 1970-01-01
    • 1970-01-01
    • 2018-08-15
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2020-09-25
    相关资源
    最近更新 更多