iOS OAuth 签名生成? [英] iOS OAuth signature generation?

查看:33
本文介绍了iOS OAuth 签名生成?的处理方法,对大家解决问题具有一定的参考价值,需要的朋友们下面随着小编来一起学习吧!

问题描述

我一直在寻找为 Oauth 标头生成签名的代码,这让我很痛苦.我的目标平台是 iOS,我需要为 TradeKing API 执行此操作.基本上,他们的查询需要 OAuth(无需使用 Oauth 工作流程提前授权我的应用程序供个人使用;我只需要使用 TradeKing 提供给我的密钥使用 oauth 标头对每个查询进行签名).以下是一些示例文档:GetPost

I've been looking for code that generates a signature for an Oauth header, and boy has that been painful. My target platform is iOS, and I need to do this for the TradeKing API. Basically their queries require OAuth (no need to authorize my app for personal use ahead of time using an Oauth workflow; I just need to sign each query with an oauth header using the keys that TradeKing provided me). Here's some example documentation: GetPost

我发现的最好的示例代码如下:https://github.com/Christian-Hansen/simple-oauth1

The best example code I have found is the following: https://github.com/Christian-Hansen/simple-oauth1

我能够效仿他的做法并显示 LinkedIn 图书馆登录信息.然后我修改了 TradeKing REST 查询的代码,但由于签名无效而失败.这让我很担心,因为生成签名的代码是最复杂的部分……而且我不确定我是否正确使用了他的代码.在下面的代码中,我将 oauth 密钥和机密更改为 X.

I was able to follow his example and get the LinkedIn library login show up. I then adapted the code for a TradeKing REST query, and it failed because of an invalid signature. That has me concerned because the code that generates the signature is the most complicated part...and I'm not sure if I am using his code properly. In the code below I changed the oauth keys and secrets into Xs.

/* THE URL REQUEST */
NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:@"https://api.tradeking.com/v1/market/ext/quotes.xml?symbols=aapl"]];
request.HTTPMethod = @"GET";

/* OAUTH FIELDS */
NSString *oauth_timestamp = [NSString stringWithFormat:@"%lu", (unsigned long)[NSDate.date timeIntervalSince1970]];
NSString *oauth_nonce = [NSString getNonce];
NSString *oauth_consumer_key = @"xxxxxxx"; 
NSString *oauth_token = @"xxxxxxx";
NSString *oauth_signature_method = @"HMAC-SHA1";
NSString *oauth_version = @"1.0";
NSMutableDictionary *standardParameters = [NSMutableDictionary dictionary];
[standardParameters setValue:oauth_consumer_key     forKey:@"oauth_consumer_key"];
[standardParameters setValue:oauth_nonce            forKey:@"oauth_nonce"];
[standardParameters setValue:oauth_signature_method forKey:@"oauth_signature_method"];
[standardParameters setValue:oauth_timestamp        forKey:@"oauth_timestamp"];
[standardParameters setValue:oauth_version          forKey:@"oauth_version"];
[standardParameters setValue:oauth_token    forKey:@"oauth_token"];
NSString *parametersString = CHQueryStringFromParametersWithEncoding(standardParameters, NSUTF8StringEncoding);

/* OAUTH SIGNATURE */
NSString *request_url = @"https://api.tradeking.com/v1/market/ext/quotes.xml?symbols=aapl";
NSString *oauth_consumer_secret = @"xxxxxx";
NSString *oauth_token_secret = @"xxxx";
NSString *baseString = [@"GET" stringByAppendingFormat:@"&%@&%@", request_url.utf8AndURLEncode, parametersString.utf8AndURLEncode];
// append oauth token secret to consumer secret
NSString *secretString = [oauth_consumer_secret.utf8AndURLEncode stringByAppendingFormat:@"&%@", oauth_token_secret.utf8AndURLEncode];
NSString *oauth_signature = [self.class signClearText:baseString withSecret:secretString];
standardParameters[@"oauth_signature"] = oauth_signature;

/* CREATE HEADER */
NSMutableArray *parameterPairs = [NSMutableArray array];
for (NSString *name in standardParameters)
{
  NSString *aPair = [name stringByAppendingFormat:@"=\"%@\"", [standardParameters[name] utf8AndURLEncode]];
  [parameterPairs addObject:aPair];
}
NSString *oAuthHeader = [@"OAuth " stringByAppendingFormat:@"%@", [parameterPairs componentsJoinedByString:@", "]];
[request setValue:oAuthHeader forHTTPHeaderField:@"Authorization"];

/* REQUEST */
[NSURLConnection sendAsynchronousRequest:request
                                 queue:[NSOperationQueue mainQueue]
                     completionHandler:^(NSURLResponse *response, NSData *data, NSError *error) {
                       NSString *reponseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding];
                       NSLog(@"Response string: %@, error: %@", reponseString, error);

                     }];

我得到的回复是signature_invalid".无论如何,我省略了与 url 编码和签名生成相关的部分,因为它们可能会占用太多空间.我想知道我是否在这里犯了错误,或者创建签名的实际函数是否有问题.

And the response I get back is "signature_invalid." Anyway, I left out the portions related to url encoding and the signature generation because they would probably take too much space. I was wondering if I made a mistake here, or if there is something wrong with the actual function that creates the signature.

推荐答案

事实证明签名创建部分 (HMAC-SHA1) 是正确的.我只需要在执行 HTTP 请求之前从标头中删除符号,否则 OAUTH 请求会认为签名与请求本身不匹配.固定代码:

It turns out the signature creation part (HMAC-SHA1) was correct. I just needed to remove the symbols from the header before the doing the HTTP request, or else the OAUTH request would think that the signature would not match the request itself. The fixed code:

// this is a convenience function for oauth
- (NSData *)fetchDataForURL:(NSString *)url paramPairs:(NSArray *)paramPairs error:(NSError**)error response:(NSHTTPURLResponse**)response timeOut:(float)timeOut {

  NSMutableString *mutableURL = [[NSMutableString alloc] init];
  [mutableURL appendString:url];
  int paramPairCount = 0;
  for (OPTTradeKingParamPair *paramPair in paramPairs) {
    if (paramPairCount > 0)
      [mutableURL appendString:@"&"];
    [mutableURL appendFormat:@"%@=", paramPair.param];
    int argCount = 0;
    for (NSString *arg in paramPair.args) {
      if (argCount > 0)
        [mutableURL appendString:@","];
      [mutableURL appendFormat:@"%@", arg];
      argCount++;
    }
    paramPairCount++;
  }

  //NSLog(@"URL request: %@", mutableURL);
  NSMutableURLRequest *request = [NSMutableURLRequest requestWithURL:[NSURL URLWithString:mutableURL] cachePolicy:NSURLRequestReloadIgnoringLocalCacheData timeoutInterval:5];
  request.HTTPMethod = @"GET";

  // oauth fields
  NSString *oauth_timestamp = [NSString stringWithFormat:@"%lu", (unsigned long)[NSDate.date timeIntervalSince1970]];
  NSString *oauth_nonce = [NSString getNonce];
  NSString *oauth_consumer_key = @"*****";
  NSString *oauth_token = @"*****";
  NSString *oauth_signature_method = @"HMAC-SHA1";
  NSString *oauth_version = @"1.0";

  NSMutableDictionary *standardParameters = [NSMutableDictionary dictionary];
  [standardParameters setValue:oauth_consumer_key     forKey:@"oauth_consumer_key"];
  [standardParameters setValue:oauth_nonce            forKey:@"oauth_nonce"];
  [standardParameters setValue:oauth_signature_method forKey:@"oauth_signature_method"];
  [standardParameters setValue:oauth_timestamp        forKey:@"oauth_timestamp"];
  [standardParameters setValue:oauth_version          forKey:@"oauth_version"];
  [standardParameters setValue:oauth_token            forKey:@"oauth_token"];

  NSMutableArray *paramPairKeys = [[NSMutableArray alloc] init];
  for (OPTTradeKingParamPair *paramPair in paramPairs) {
    NSString *key = paramPair.param;
    NSMutableString *args = [[NSMutableString alloc] init];

    int argCount = 0;
    for (NSString *arg in paramPair.args) {
      if (argCount > 0)
        [args appendString:@","];
      [args appendFormat:@"%@", arg];
    }

    [standardParameters setValue:args forKey:key];
    [paramPairKeys addObject:key];
  }

  NSString *parametersString = CHQueryStringFromParametersWithEncoding(standardParameters, NSUTF8StringEncoding);
  // use URL and remove ? (always at end of URL)
  NSString *request_url = [url stringByReplacingOccurrencesOfString:@"?" withString:@""];
  NSString *oauth_consumer_secret = @"*****";
  NSString *oauth_token_secret = @"*****";
  NSString *baseString = [@"GET" stringByAppendingFormat:@"&%@&%@", request_url.utf8AndURLEncode, parametersString.utf8AndURLEncode];
  // append oauth token secret to consumer secret
  NSString *secretString = [oauth_consumer_secret.utf8AndURLEncode stringByAppendingFormat:@"&%@", oauth_token_secret.utf8AndURLEncode];
  NSString *oauth_signature = [self.class signClearText:baseString withSecret:secretString];
  standardParameters[@"oauth_signature"] = oauth_signature;

  // remove symbols portion for header before doing request
  for (NSString* keyToRemove in paramPairKeys) {
    [standardParameters removeObjectForKey:keyToRemove];
  }
  [standardParameters removeObjectForKey:@"symbols"];

  NSMutableArray *parameterPairs = [NSMutableArray array];
  for (NSString *name in standardParameters)
  {
    NSString *aPair = [name stringByAppendingFormat:@"=\"%@\"", [standardParameters[name] utf8AndURLEncode]];
    [parameterPairs addObject:aPair];
  }
  parameterPairs = [NSMutableArray arrayWithArray:[parameterPairs sortedArrayUsingSelector:@selector(localizedCaseInsensitiveCompare:)]];

  NSString *oAuthHeader = [@"OAuth " stringByAppendingFormat:@"%@", [parameterPairs componentsJoinedByString:@", "]];
  [request setValue:oAuthHeader forHTTPHeaderField:@"Authorization"];

  NSData * data = [NSURLConnection sendSynchronousRequest:request returningResponse:response error:error];
  [OPTCrashModule addErrorWithData:data error:*error];
  return data;
}

<小时>

如何调用代码:


How to call the code:

- (DataAPIReturnVal)findInfoForSymbols:(NSArray*)tickerSymbols returnedTickerInfos:(NSMutableArray *)tickerInfos
{
  NSMutableString *symbols = [[NSMutableString alloc] init];
  int index = 0;
  for(NSString *tickerSymbol in tickerSymbols)
  {
    if (index > 0) [symbols appendString:@","];
    OPTTickerInfo *tickerInfo = [[OPTTickerInfo alloc] init];
    [tickerInfo setName:tickerSymbol];
    [tickerInfos addObject:tickerInfo];
    [symbols appendString:[tickerSymbol uppercaseString]];
    index++;
  }

  NSMutableArray *paramPairs = [[NSMutableArray alloc] init];
  OPTTradeKingParamPair *paramPair = [[OPTTradeKingParamPair alloc] initWithParam:@"symbols" args:@[symbols]];
  [paramPairs addObject:paramPair];

  DataAPIReturnVal retVal = DataAPIGeneralError;
  NSHTTPURLResponse *response = nil;
  NSError *error = nil;
  NSData * retData = [self     fetchDataForURL:@"https://api.tradeking.com/v1/market/ext/quotes.json?" paramPairs:paramPairs error:&error response:&response timeOut:[tickerSymbols count]];
// ....and so on
}

<小时>

Param 对只是一个对象数组,其中每个对象都是一个param"字符串和args"数组.参数可以是符号"之类的东西,而参数"可以是实际的符号参数,即 fas、faz、msft 等.


Param pairs is simply an array of objects, where each object is a "param" string and and "args" array. Param can be something like "symbols" and the "args" can the actual symbol arguments i.e. fas, faz, msft, etc.

人们要求的额外内容:

- (NSString *)signClearText:(NSString *)text withSecret:(NSString *)secret
{
  NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding];
  NSData *clearTextData = [text dataUsingEncoding:NSUTF8StringEncoding];
  unsigned char result[20];
  hmac_sha1((unsigned char *)[clearTextData bytes], [clearTextData length], (unsigned char *)[secretData bytes], [secretData length], result);

  //Base64 Encoding
  char base64Result[32];
  size_t theResultLength = 32;
  Base64EncodeData(result, 20, base64Result, &theResultLength);
  NSData *theData = [NSData dataWithBytes:base64Result length:theResultLength];

  return [NSString.alloc initWithData:theData encoding:NSUTF8StringEncoding];
}

我需要花一些时间来打包代码以供一般使用.在公众可以重复使用它之前,我还必须删除许多其他东西.

I need to spend some time packaging the code for general use. There is a bunch of other stuff I have to gut out before the general public can reuse it.

这篇关于iOS OAuth 签名生成?的文章就介绍到这了,希望我们推荐的答案对大家有所帮助,也希望大家多多支持IT屋!

查看全文
登录 关闭
扫码关注1秒登录
发送“验证码”获取 | 15天全站免登陆