V3手动鉴权失败之C#篇

2020-12-31 10:36:04 浏览数 (1)

导语

该系列其他篇章:

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桌面开发”组件安装“.NET桌面开发”组件

具体代码

点击“创建新项目”,选择“控制台应用(.NET Core)”

新建.NET控制台应用新建.NET控制台应用

配置新项目,命名为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);
        }
    }
}

0 人点赞