原创

V3手动鉴权失败之C#篇

导语

该系列其他篇章:

V3手动鉴权失败之Nodejs篇

V3手动鉴权失败之Go篇

V3手动鉴权失败之Python篇

V3手动鉴权失败之Java篇

V3手动鉴权失败之PHP篇

腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接口级注释,让您更加方便快捷的使用腾讯云产品。人脸识别文字识别语音识别等众多产品均已接入云API 3.0。

腾讯云API为了更好的让用户接入,已经封装好了多种语言的SDK,只需用户传入SecrectId、SectectKey以及接口入参,即可完成接口鉴权和请求发送,具体包括Python SDKJava SDKPHP SDKGo SDKNodeJS 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 Core)”

新建.NET控制台应用

配置新项目,命名为V3Test

配置新项目

在打开的Program.cs文件中,书写如下代码,即可完成v3鉴权,并发送http请求,收到具体的response响应。

只需要简单复制,然后输入自己的SecretId和SecretKey两个字段即可:

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-8\n" + "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%3A%2F%2F5b0988e595225.cdn.sohucs.com%2Fimages%2F20180811%2Fefb2c10f038b4749b5a3669f34f26e2c.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);
        }
    }
}

原创声明,本文系作者授权云+社区发表,未经许可,不得转载。

如有侵权,请联系 yunjia_community@tencent.com 删除。

我来说两句

0 条评论
登录 后参与评论

相关文章

  • V3手动鉴权失败之Nodejs篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Go篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Java篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之Python篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • V3手动鉴权失败之PHP篇

    腾讯云 API 全新升级 3.0 ,该版本进行了性能优化且全地域部署、支持就近和按地域接入、访问时延下降显著,接口描述更加详细、错误码描述更加全面、SDK增加接...

    周朋伟
  • 【AI接入迷你赛】腾讯云产品鉴权签名 v3

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

    用户4299935
  • 【玩转腾讯云】【腾讯云语音合成】智能语音交互之语音合成篇

    语音合成(Text To Speech,TTS)满足将文本转化成拟人化语音的需求,打通人机交互闭环。 提供多种音色选择,支持自定义音量、语速,让发音更自然、更专...

    ruskin
  • etcd 备份与恢复

    etcd 是一款开源的分布式一致性键值存储,由 CoreOS 公司进行维护,详细的介绍请参考官方文档。

    田飞雨
  • 重启导致etcd数据不一致的bug分析

    近日,腾讯云TKE团队的工程师在做混沌测试的过程中,定位并解决了一个存在3年之久的etcd3数据一致性bug。

    于广游garyyu

扫码关注云+社区

领取腾讯云代金券