腾讯云V3签名方法之iOS

时间:2022-07-22
本文章向大家介绍腾讯云V3签名方法之iOS,主要内容包括其使用实例、应用技巧、基本知识点总结和需要注意事项,具有一定的参考价值,需要的朋友可以参考一下。

签名方法 v3

签名方法 v3 (TC3-HMAC-SHA256)功能上覆盖了以前的签名方法 v1,而且更安全,支持更大的请求,支持 json 格式,性能有一定提升,推荐使用该签名方法计算签名。

首次接触,建议使用 API Explorer 中的“签名串生成”功能,选择签名版本为“API 3.0 签名 v3”,可以生成签名过程进行验证,也可直接生成 SDK 代码。推荐使用腾讯云 API 配套的 7 种常见的编程语言 SDK,已经封装了签名和请求过程,均已开源,支持 PythonJavaPHPGoNodeJS.NETC++

腾讯云 API 会对每个请求进行身份验证,用户需要使用安全凭证,经过特定的步骤对请求进行签名(Signature),每个请求都需要在公共请求参数中指定该签名结果并以指定的方式和格式发送请求。

目前提供7 种常见的编程语言SDK,封装了签名和请求过程,均已开源

有一些需求移动端直接请求接口,这时候就需要我们自己写签名了,安卓可以直接复制JAVA代码,iOS方面官方文档目前没有OC示例,也没有Swift示例

Swift示例见:https://cloud.tencent.com/developer/article/1602241

接下来我们按照腾讯云文档中的一个签名过程来实现OC的签名

https://cloud.tencent.com/document/product/866/33519

为了清晰展示签名的准确性,用户的 SecretId 和 SecretKey,以及时间戳等信息均与上述文档中保持一致

计算签名的方法:

// 计算签名
-(NSDictionary *)calculationSignature{
    
    NSString *SECRET_ID = @"AKIDz8krbsJ5yKBZQpn74WFkmLPx3EXAMPLE";
    NSString *SECRET_KEY = @"Gu5t9xGARNpq86cd98joQYCN3EXAMPLE";
    NSString *CType = @"application/json; charset=utf-8";
    NSString *service = @"cvm";
    NSString *host = @"cvm.tencentcloudapi.com";
    NSString *hostn = [host stringByAppendingString:@"n"];
    NSString *region = @"ap-guangzhou";
    NSString *action = @"DescribeInstances";
    NSString *version = @"2017-03-12";
    NSString *algorithm = @"TC3-HMAC-SHA256";
    NSString *timestamp = @"1551113065"; //此处用官方文档中的时间戳
    NSString *date = [self getUTCStr];
    
    // ************* 步骤 1:拼接规范请求串 *************
    NSString *httpRequestMethod = @"POST";
    NSString *canonicalUri = @"/";
    NSString *canonicalQueryString = @"";
    NSString *canonicalHeaders = [@"content-type:application/json; charset=utf-8nhost:" stringByAppendingString:hostn];
    NSString *signedHeaders = @"content-type;host";
    NSString *bodyStr = @"{"Limit": 1, "Filters": [{"Values": ["\u672a\u547d\u540d"], "Name": "instance-name"}]}";
    NSString *hashedRequestPayload = [self sha256HashFor:bodyStr];
    NSString *canonicalRequest= [[NSString alloc] initWithFormat:@"%@%@%@%@%@%@%@%@%@%@%@", httpRequestMethod,@"n",canonicalUri,@"n", canonicalQueryString,@"n", canonicalHeaders,@"n", signedHeaders,@"n", hashedRequestPayload];
    
    NSLog(@"第一步结果:%@%@",@"n",canonicalRequest);
    // ************* 步骤 2:拼接待签名字符串 *************
    NSString *credentialScope = [[NSString alloc]initWithFormat: @"%@%@%@%@", date,@"/",service,@"/tc3_request"];
    NSString *hashedCanonicalRequest = [self sha256HashFor:canonicalRequest];
    NSString *stringToSign = [[NSString alloc] initWithFormat:@"%@%@%@%@%@%@%@", algorithm,@"n",timestamp,@"n",credentialScope,@"n",hashedCanonicalRequest];
    NSLog(@"第二步结果:%@%@",@"n",stringToSign);
    // ************* 步骤 3:计算签名 *************
    
   
    NSString * key1 = [self hexStringFromString:[@"TC3" stringByAppendingString:SECRET_KEY]];
    NSString *secretDate = [self hmacForHexKey:key1 andStringData:date];
//    NSLog(@"secretDate:%@", secretDate);
    NSString *secretService = [self hmacForHexKey:secretDate andStringData:service];
//    NSLog(@"secretService:%@", secretService);
    NSString *secretSigning = [self hmacForHexKey:secretService andStringData:@"tc3_request"];
//    NSLog(@"secretSigning:%@", secretSigning);
    NSString *signature = [self hmacForHexKey:secretSigning andStringData:stringToSign];
    NSLog(@"第三步结果:%@%@",@"n",signature);
    // ************* 步骤 4:拼接 Authorization *************
    NSString *authorization = [[NSString alloc] initWithFormat: @"%@ Credential=%@/%@, SignedHeaders=%@, Signature=%@",algorithm,SECRET_ID,credentialScope, signedHeaders, signature];
    NSLog(@"第四步结果:%@%@",@"n",authorization);
    NSDictionary *dic = @{
        @"URL": [@"https://" stringByAppendingString:host],
        @"Authorization": authorization,
        @"ContentType": CType,
        @"Host": host,
        @"X-TC-Action": action,
        @"X-TC-Version": version,
        @"X-TC-Timestamp": timestamp,
        @"X-TC-Region": region,
    };
    NSLog(@"最终完整的调用信息:%@%@",@"n",dic);
    return dic;
}

各步骤结果验证:

结果验证

每一步结果都与https://cloud.tencent.com/document/product/866/33519

文档中的结果一致,说明签名准确无误

计算签名方法中调用到的其他方法如下:

//SHA256加密
-(NSString*)sha256HashFor:(NSString*)input{
    const char* str = [input UTF8String];
    unsigned char result[CC_SHA256_DIGEST_LENGTH];
    CC_SHA256(str, (CC_LONG)strlen(str), result);
    
    NSMutableString *ret = [NSMutableString stringWithCapacity:CC_SHA256_DIGEST_LENGTH*2];
    for(int i = 0; i<CC_SHA256_DIGEST_LENGTH; i++)
    {
        [ret appendFormat:@"%02x",result[i]];
    }
    ret = (NSMutableString *)[ret uppercaseString];
    return [ret lowercaseString];
}

// hmac256加密
- (NSString *)hmacForHexKey:(NSString *)hexkey andStringData:(NSString *)data
{
    NSData *keyData = [self dataFromHexString:hexkey];
    const char *cKey  = [keyData bytes];
    const char *cData = [data cStringUsingEncoding:NSUTF8StringEncoding];
    unsigned char cHMAC[CC_SHA256_DIGEST_LENGTH];
    CCHmac(kCCHmacAlgSHA256, cKey, keyData.length, cData, strlen(cData), cHMAC);
    return  [self convertDataToHexStr: [[NSData alloc] initWithBytes:cHMAC length:sizeof(cHMAC)]];
}

- (NSString *)convertDataToHexStr:(NSData *)data{
    if (!data || [data length] == 0) {
        return @"";
    }
    NSMutableString *string = [[NSMutableString alloc] initWithCapacity:[data length]];
    [data enumerateByteRangesUsingBlock:^(const void *bytes, NSRange byteRange, BOOL *stop) {
        unsigned char *dataBytes = (unsigned char*)bytes;
        for (NSInteger i = 0; i < byteRange.length; i++) {
            NSString *hexStr = [NSString stringWithFormat:@"%x", (dataBytes[i]) & 0xff];
            if ([hexStr length] == 2) {
                [string appendString:hexStr];
            } else {
                [string appendFormat:@"0%@", hexStr];
            }
        }
    }];
    return string;
}

// 获取UTC时间
-(NSString *)getUTCStr{
    NSTimeInterval time = 1551113065;//此处使用腾讯云文档中的时间戳,实际请求时需要获取当前时间
    NSDate *currentDate = [NSDate dateWithTimeIntervalSince1970:(NSTimeInterval)time];
    //转为字符串
    NSDateFormatter *format = [[NSDateFormatter alloc]init];
    NSTimeZone* timeZone = [NSTimeZone timeZoneForSecondsFromGMT:0];
    [format setTimeZone:timeZone];
    [format setDateFormat:@"yyyy-MM-dd"];
    return [format stringFromDate:currentDate];
}

// string 转data
- (NSData *)dataFromHexString:(NSString *)sHex {
    const char *chars = [sHex UTF8String];
    int i = 0;
    NSUInteger len = sHex.length;
    NSMutableData *data = [NSMutableData dataWithCapacity:len / 2];
    char byteChars[3] = {'','',''};
    unsigned long wholeByte;
    while (i < len) {
        byteChars[0] = chars[i++];
        byteChars[1] = chars[i++];
        wholeByte = strtoul(byteChars, NULL, 16);
        [data appendBytes:&wholeByte length:1];
    }
    return data;
}

// 普通转为16进制
- (NSString *)hexStringFromString:(NSString *)string{
    NSData *myD = [string dataUsingEncoding:NSUTF8StringEncoding];
    Byte *bytes = (Byte *)[myD bytes];
    //下面是Byte 转换为16进制。
    NSString *hexStr=@"";
    for(int i=0;i<[myD length];i++)
    {
        NSString *newHexStr = [NSString stringWithFormat:@"%x",bytes[i]&0xff];///16进制数
        if([newHexStr length]==1)
            hexStr = [NSString stringWithFormat:@"%@0%@",hexStr,newHexStr];
        else
            hexStr = [NSString stringWithFormat:@"%@%@",hexStr,newHexStr];
    }
    return hexStr;
}

参考

OC : https://github.com/williammyuan/tencentcloud-ios

Swift : https://cloud.tencent.com/developer/article/1602241

这篇文章对您有帮助的话,记得给小编点个赞 !