导语
该系列其他篇章:
V3手动鉴权失败之Nodejs篇
V3手动鉴权失败之Go篇
V3手动鉴权失败之Python篇
V3手动鉴权失败之Java篇
V3手动鉴权失败之PHP篇
腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接口级注释,让您更加方便快捷的使用腾讯云产品。人脸识别、文字识别,语音识别等众多产品均已接入云API 3.0。
腾讯云API为了更好的让用户接入,已经封装好了多种语言的SDK,只需用户传入SecrectId、SectectKey以及接口入参,即可完成接口鉴权和请求发送,具体包括Python SDK、Java SDK、PHP SDK、Go SDK、NodeJS SDK、.NET SDK。
案例背景
在某些情况,用户需要实现手动接口鉴权,虽然官网文档已有详细的接口鉴权流程,但是由于:
1.V3手动鉴权步骤较为复杂;
2.官网某些demo代码无法直接下载运行,仍需简单调整;
3.官网文档的demo代码覆盖面有限,没有包括全量上述六类后端语言;
基于此,很多用户只能自己尝试手动鉴权,但都返回“鉴权失败”,从而无法调通接口。
原因分析
从宏观上看,“鉴权失败”要关注两个阶段:
1. 整体的接口鉴权是否正确;
2. 模拟的鉴权请求的发送是否正确;
从历史问题回顾,有客户曾经出现接口鉴权时而成功,时而失败的情况,排查了整体的鉴权过程,完全正确,但是也的确复现了客户的问题。后来发现,用户在鉴权完成后,发送具体的请求时,传入的时间戳timestamp没有实时更新导致了报错。
解决方案
为了帮助客户更简单、更快捷地完成接口手动鉴权,并成功发送鉴权请求,将通过一系列文章专门讲解各个后端语言的手动鉴权&发送请求的可执行demo代码,助力客户快速接入。
本期将以调用人脸识别的DetectFace接口为例,详叙C#语言
控制台应用demo。
前期准备
SecrectId和SecretKey:接口鉴权的密钥。可以把SecretId理解成“账号”,把SecretKey理解成“密码”。在自己的腾讯云官网控制台获取:访问管理 -> 访问密钥 -> API密钥管理。
手动鉴权相关文档:请求结构、公共参数、V3接口鉴权
C#语言环境:笔者使用visual studio 2019 社区版。因为控制台应用需要安装“.NET 桌面开发”组件,首次使用时,点击“创建新项目”后,无法找到该组件,需要点击“安装多个工具和功能”进行安装。
点击“安装多个工具和功能”后,选择“.Net桌面开发”进行下载安装即可。
具体代码
点击“创建新项目”,选择“控制台应用(.NET Core)”
配置新项目,命名为V3Test
在打开的Program.cs文件中,书写如下代码,即可完成v3鉴权,并发送http请求,收到具体的response响应。
只需要简单复制,然后输入自己的SecretId和SecretKey两个字段即可:
代码语言:javascript复制using System;
using System.Collections.Generic;
using System.Security.Cryptography;
using System.Text;
using System.Net;
using System.IO; // for StreamReader
namespace V3Test
{
class Program
{
public static string SHA256Hex(string s)
{
using (SHA256 algo = SHA256.Create())
{
byte[] hashbytes = algo.ComputeHash(Encoding.UTF8.GetBytes(s));
StringBuilder builder = new StringBuilder();
for (int i = 0; i < hashbytes.Length; i)
{
builder.Append(hashbytes[i].ToString("x2"));
}
return builder.ToString();
}
}
public static byte[] HmacSHA256(byte[] key, byte[] msg)
{
using (HMACSHA256 mac = new HMACSHA256(key))
{
return mac.ComputeHash(msg);
}
}
public static Dictionary<String, String> BuildHeaders(string secretid,
string secretkey, string service, string endpoint, string region,
string action, string version, DateTime date, string requestPayload)
{
string datestr = date.ToString("yyyy-MM-dd");
Console.WriteLine(datestr);
DateTime startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
long requestTimestamp = (long)Math.Round((date - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero) / 1000;
Console.WriteLine(requestTimestamp);
// ************* 步骤 1:拼接规范请求串 *************
string algorithm = "TC3-HMAC-SHA256";
string httpRequestMethod = "POST";
string canonicalUri = "/";
string canonicalQueryString = "";
string contentType = "application/json";
string canonicalHeaders = "content-type:" contentType "; charset=utf-8n" "host:" endpoint "n";
string signedHeaders = "content-type;host";
string hashedRequestPayload = SHA256Hex(requestPayload);
string canonicalRequest = httpRequestMethod "n"
canonicalUri "n"
canonicalQueryString "n"
canonicalHeaders "n"
signedHeaders "n"
hashedRequestPayload;
Console.WriteLine(canonicalRequest);
Console.WriteLine("----------------------------------");
// ************* 步骤 2:拼接待签名字符串 *************
string credentialScope = datestr "/" service "/" "tc3_request";
string hashedCanonicalRequest = SHA256Hex(canonicalRequest);
string stringToSign = algorithm "n" requestTimestamp.ToString() "n" credentialScope "n" hashedCanonicalRequest;
Console.WriteLine(stringToSign);
Console.WriteLine("----------------------------------");
// ************* 步骤 3:计算签名 *************
byte[] tc3SecretKey = Encoding.UTF8.GetBytes("TC3" secretkey);
byte[] secretDate = HmacSHA256(tc3SecretKey, Encoding.UTF8.GetBytes(datestr));
byte[] secretService = HmacSHA256(secretDate, Encoding.UTF8.GetBytes(service));
byte[] secretSigning = HmacSHA256(secretService, Encoding.UTF8.GetBytes("tc3_request"));
byte[] signatureBytes = HmacSHA256(secretSigning, Encoding.UTF8.GetBytes(stringToSign));
string signature = BitConverter.ToString(signatureBytes).Replace("-", "").ToLower();
Console.WriteLine(signature);
Console.WriteLine("----------------------------------");
// ************* 步骤 4:拼接 Authorization *************
string authorization = algorithm " "
"Credential=" secretid "/" credentialScope ", "
"SignedHeaders=" signedHeaders ", "
"Signature=" signature;
Console.WriteLine(authorization);
Console.WriteLine("----------------------------------");
Dictionary<string, string> headers = new Dictionary<string, string>();
headers.Add("Authorization", authorization);
headers.Add("Host", endpoint);
headers.Add("Content-Type", contentType "; charset=utf-8");
headers.Add("X-TC-Timestamp", requestTimestamp.ToString());
headers.Add("X-TC-Version", version);
headers.Add("X-TC-Action", action);
headers.Add("X-TC-Region", region);
return headers;
}
static void Main(string[] args)
{
// 密钥参数
string SECRET_ID = "xxx";//输入自己的secretId
string SECRET_KEY = "xxx";//输入自己的secretKey
string service = "iai";
string endpoint = "iai.tencentcloudapi.com";
string region = "ap-guangzhou";
string action = "DetectFace";
string version = "2020-03-03";
// 此处由于示例规范的原因,采用时间戳2019-02-26 00:44:25,此参数作为示例,如果在项目中,您应当使用:
// DateTime date = DateTime.UtcNow;
// 注意时区,建议此时间统一采用UTC时间戳,否则容易出错
DateTime date = DateTime.UtcNow;
Console.WriteLine(date);
string requestPayload = "{"Url": "https://timgsa.baidu.com/timg?image&quality=80&size=b9999_10000&sec=1601296547571&di=2152789b1c2c00459485f2bc57181c94&imgtype=0&src=http://5b0988e595225.cdn.sohucs.com/images/20180811/efb2c10f038b4749b5a3669f34f26e2c.jpeg"}";
Dictionary<string, string> headers = BuildHeaders(SECRET_ID, SECRET_KEY, service
, endpoint, region, action, version, date, requestPayload);
Console.WriteLine("POST https://iai.tencentcloudapi.com");
Console.WriteLine();
Console.WriteLine(requestPayload);
var request = (HttpWebRequest)WebRequest.Create("https://iai.tencentcloudapi.com");
var data = Encoding.UTF8.GetBytes(requestPayload);
request.Method = "POST";
//request.ContentType = "application/json";
foreach (KeyValuePair<string, string> kv in headers)
{
//Console.WriteLine(kv.Key ": " kv.Value);
request.Headers.Add(kv.Key, kv.Value);
}
request.ContentLength = data.Length;
using (var stream = request.GetRequestStream())
{
stream.Write(data, 0, data.Length);
}
var response = (HttpWebResponse)request.GetResponse();
var responseString = new StreamReader(response.GetResponseStream()).ReadToEnd();
Console.WriteLine(responseString);
}
}
}