如何在Objective-C中获得QuickBlox令牌

由于工作限制,必须使用Quickblox的RESTful API而不是iOS SDK,并且在根据教程生成有效签名时遇到问题。

以下是我的电话回复:

2014-07-25 16:19:12.646 test[2247:60b]response: <NSHTTPURLResponse: 0x10c41ae40> { URL:https://api.quickblox.com/session.json } { status code: 422, headers { "Access-Control-Allow-Origin" = "*"; "Cache-Control" = "no-cache"; Connection = "keep-alive"; "Content-Type" = "application/json; charset=utf-8"; Date = "Fri, 25 Jul 2014 23:19:12 GMT"; "QuickBlox-REST-API-Version" = "0.1.1"; Server = "nginx/1.0.15"; Status = "422 Unprocessable Entity"; "Transfer-Encoding" = Identity; "X-Rack-Cache" = "invalidate, pass"; "X-Request-Id" = 8413fb7182cee06857619b14f363ed78; "X-Runtime" = "0.004821"; "X-UA-Compatible" = "IE=Edge,chrome=1"; } } data: {"errors":{"base":["Unexpected signature"]}} connectionError: (null) 

以下是我正在使用的方法:

 - (void) retrieveQBTokenTest{ // Authentication data NSString *appId = @"12345"; NSString *authKey = @"ypqdqEx7sOeWEQr"; NSString *timestamp = [NSString stringWithFormat:@"%.0f", [[NSDate date] timeIntervalSince1970]]; NSString *nonce = [NSString stringWithFormat:@"%i", (arc4random()%1000)+1]; NSString *authSecret = @"dtoA5bkNrBUZn5L"; NSString *dataStringForSig = [NSString stringWithFormat:@"application_id=%@&auth_key=%@&nonce=%@&timestamp=%@", appId, authKey, nonce, timestamp]; NSString *sig = [self hmacsha1:dataStringForSig secret:authSecret]; // Package authentication data into JSON NSDictionary *dict = @{ @"application_id":appId, @"auth_key":authKey, @"timestamp":timestamp, @"nonce":nonce, @"signature":sig }; NSError *error; NSData *jsonData = [NSJSONSerialization dataWithJSONObject:dict options:0 error:&error]; NSLog(@"%s: jsonString: %@", __FUNCTION__, [[NSString alloc]initWithData:jsonData encoding:NSUTF8StringEncoding]); // Generate request NSURL *url = [NSURL URLWithString:@"https://api.quickblox.com/session.json"]; NSMutableURLRequest *request = [[NSMutableURLRequest alloc] initWithURL:url]; // Headers [request setHTTPMethod:@"POST"]; [request setValue:@"0.1.1" forHTTPHeaderField:@"QuickBlox-REST-API-Version"]; [request setValue:@"application/json" forHTTPHeaderField:@"Content-Type"]; NSString *length = [NSString stringWithFormat:@"%lu", (unsigned long)[jsonData length]]; [request setValue:length forHTTPHeaderField:@"Content-Length"]; // Body [request setHTTPBody:jsonData]; // Make call [NSURLConnection sendAsynchronousRequest:request queue:[NSOperationQueue mainQueue] completionHandler:^(NSURLResponse *response, NSData *data, NSError *connectionError) { NSString *dataResponseString = [[NSString alloc] initWithData:data encoding:NSUTF8StringEncoding]; NSLog(@"%s: response: %@ data: %@ connectionError: %@", __FUNCTION__, response, dataResponseString, connectionError); }]; } 

最后,我的哈希方法:

 - (NSString *)hmacsha1:(NSString *)data secret:(NSString *)key { const char *cKey = [key cStringUsingEncoding:NSASCIIStringEncoding]; const char *cData = [data cStringUsingEncoding:NSASCIIStringEncoding]; unsigned char cHMAC[CC_SHA1_DIGEST_LENGTH]; CCHmac(kCCHmacAlgSHA1, cKey, strlen(cKey), cData, strlen(cData), cHMAC); NSData *HMAC = [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]; NSString *hash = [HMAC base64EncodedStringWithOptions:0]; return hash; } 

看起来像我生成签名的方式是不好的,但不知道我搞乱了。 有什么build议么?

这是一个合适的签名生成方法:

 + (NSString *)signData:(NSData *)data withSecret:(NSString *)secret{ NSData *secretData = [secret dataUsingEncoding:NSUTF8StringEncoding]; NSData *clearTextData = data; uint8_t digest[CC_SHA1_DIGEST_LENGTH] = {0}; CCHmacContext hmacContext; CCHmacInit(&hmacContext, kCCHmacAlgSHA1, secretData.bytes, secretData.length); CCHmacUpdate(&hmacContext, clearTextData.bytes, clearTextData.length); CCHmacFinal(&hmacContext, digest); NSData *result = [NSData dataWithBytes:digest length:CC_SHA1_DIGEST_LENGTH]; NSString *hash = [result description]; hash = [hash stringByReplacingOccurrencesOfString:@" " withString:@""]; hash = [hash stringByReplacingOccurrencesOfString:@"<" withString:@""]; hash = [hash stringByReplacingOccurrencesOfString:@">" withString:@""]; return hash; } 

和用法:

 [SignHelper signData:[self rawBodyWithoutEncode] withSecret:[QBSettings authorizationSecret]] - (NSData *)rawBodyWithoutEncode { NSData *raw = nil; NSMutableString *params = [[NSMutableString alloc] init]; // sort NSMutableArray *sortKeys = [NSMutableArray arrayWithArray:[parameters allKeys]]; [sortKeys sortUsingSelector:@selector(compare:)]; for (id s in sortKeys){ [params appendFormat:@"%@=%@&", s, [parameters objectForKey:s]]; } [params deleteCharactersInRange:NSMakeRange([params length] - 1, 1)]; raw = [params dataUsingEncoding:NSUTF8StringEncoding]; return raw; } 

 NSMutableDictionary *params = [NSMutableDictionary dictionary]; NSUInteger appID = [QBSettings applicationID]; NSString *authKey = [QBSettings authorizationKey]; NSUInteger nonce = arc4random()%1000; NSUInteger timestamp = [[NSDate date] timeIntervalSince1970]; [params setValue:[NSString stringWithFormat:@"%lu",(unsigned long)appID] forKey:@"application_id"]; [params setValue:authKey forKey:@"auth_key"]; [params setValue:[NSString stringWithFormat:@"%lu",(unsigned long)nonce] forKey:@"nonce"]; [params setValue:[NSString stringWithFormat:@"%lu",(unsigned long)timestamp] forKey:@"timestamp"];