前往小程序,Get更优阅读体验!
立即前往
首页
学习
活动
专区
工具
TVP
发布
社区首页 >专栏 >V3手动鉴权失败之C#篇

V3手动鉴权失败之C#篇

原创
作者头像
周朋伟
发布2020-12-31 10:36:04
1.9K0
发布2020-12-31 10:36:04
举报

导语

该系列其他篇章:

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桌面开发”组件

具体代码

点击“创建新项目”,选择“控制台应用(.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-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);
        }
    }
}

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

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

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

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

评论
登录后参与评论
0 条评论
热度
最新
推荐阅读
目录
  • 导语
  • 案例背景
  • 原因分析
  • 解决方案
    • 前期准备
      • 具体代码
      相关产品与服务
      云 API
      云 API 是腾讯云开放生态的基石。通过云 API,只需少量的代码即可快速操作云产品;在熟练的情况下,使用云 API 完成一些频繁调用的功能可以极大提高效率;除此之外,通过 API 可以组合功能,实现更高级的功能,易于自动化, 易于远程调用, 兼容性强,对系统要求低。
      领券
      问题归档专栏文章快讯文章归档关键词归档开发者手册归档开发者手册 Section 归档