带有令牌认证的 NSURLSession
Posted
技术标签:
【中文标题】带有令牌认证的 NSURLSession【英文标题】:NSURLSession with Token Authentication 【发布时间】: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 发送身份验证数据? 【参考方案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 我更新了我的帖子以反映这一点。以上是关于带有令牌认证的 NSURLSession的主要内容,如果未能解决你的问题,请参考以下文章