2014-10-16 3 views
3

나는 Oauth 헤더에 대한 서명을 생성하는 코드를 찾고 있었고 소년은 고통 스럽습니다. 내 타겟 플랫폼은 IOS이며 TradeKing API를 위해이 작업을 수행해야합니다. 기본적으로 쿼리에는 OAuth가 필요합니다 (Oauth 워크 플로를 사용하여 개인용으로 앱을 미리 인증 할 필요가 없으며 TradeKing에서 제공 한 키를 사용하여 각 쿼리에 oauth 헤더로 서명해야합니다). 다음은 몇 가지 예를 들어 문서입니다 : GetPostiOS OAuth 서명 생성?

내가 찾은 가장 좋은 예제 코드는 다음과 같습니다 : 나는 그의 모범을 따라 링크드 라이브러리 로그인 쇼를 위로 얻을 수 있었다 https://github.com/Christian-Hansen/simple-oauth1

. 그런 다음 TradeKing REST 쿼리의 코드를 수정했으며 잘못된 서명으로 인해 실패했습니다. 서명을 생성하는 코드가 가장 복잡한 부분이기 때문에 걱정됩니다. 코드를 올바르게 사용하고 있는지 확실하지 않습니다. 아래의 코드에서 oauth 키와 비밀 키를 X로 변경했습니다.

/* 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 인코딩 및 서명 생성과 관련된 부분은 너무 많은 공간이 필요하기 때문에 생략했습니다. 여기서 실수를했는지, 아니면 서명을 생성하는 실제 기능에 문제가 있는지 궁금합니다.

+1

'CHQueryStringFromParametersWithEncoding'은 매개 변수가 알파벳 순서로되어 있는지 확인합니까? –

+0

좋은 점 Stephen ... 여기 있습니다 : parameters 설명 문자열 인쇄 : oauth_consumer_key = xxxx & oauth_nonce = xxxx & oauth_signature_method = HMAC-SHA1 & oauth_timestamp = xxxx & oauth_token = xxxxx8 & oauth_version = 1.0 그래서 예, 알파벳 순으로 정렬됩니다. 나는 심지어 그 함수에서 수동으로 그들을 정렬하고 나는 같은 에러를 얻는다. – luxchar

답변

1

서명 생성 부분 (HMAC-SHA1)이 정확한 것으로 판명되었습니다. HTTP 요청을하기 전에 헤더에서 심볼을 제거하기 만하면 OAUTH 요청은 서명이 요청 자체와 일치하지 않는다고 생각할 것입니다. 고정 코드 :


// 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; 
} 

어떻게 코드 전화 :

- (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"입니다 객체의 배열입니다 문자열 및 및 "args"배열. 파람는 "상징"및 "인수"같은 것을 할 수있는 실제 심볼 인수 등 FAS, FAZ, MSFT를, 즉 수

사람들이 요청한 것을

추가 재료 :

- (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]; 
} 

내가 몇 가지를 보낼 필요 일반적인 사용을위한 코드를 패키징합니다. 일반 대중이 그것을 재사용하기 전에 나가야하는 다른 것들이 많이 있습니다.

+0

여기에 signClearText는 무엇인가? –

+1

OPTTradeKingParamPair 무엇입니까? –

+0

코드를 사용하여 프로젝트로 예제 zip을 만들 수 있습니까? –