最近有个需求需要调用腾讯语音合成Api。使用的V3鉴权,一直提示如下错误

{"Response":{"Error":{"Code":"AuthFailure.SignatureFailure","Message":"The provided credentials could not be validated. Please check your signature is correct."},"RequestId":"60650a2f-e2a3-498b-8af2-fb334a27610a"}}

和官网的ApiExplorer中的生成签名一步步核对,发现和接口文档中的demo的最大区别是接口demo 中编码方式,ApiExplorer中没有,看了一些帖子说是这里上下要保持一致。因为要排查报错原因,这里改成和ApiExplorer中一样。具体代码如下:

private 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");
            DateTime startTime = new DateTime(1970, 1, 1, 0, 0, 0, 0, DateTimeKind.Utc);
            long requestTimestamp = (long)Math.Round((date - startTime).TotalMilliseconds, MidpointRounding.AwayFromZero) / 1000;//请求时间戳
            // ************* 步骤 1:拼接规范请求串 *************
            string algorithm = "TC3-HMAC-SHA256";//签名算法
            string httpRequestMethod = "POST";
            string canonicalUri = "/";//Api3.0固定为正斜杠(/)
            string canonicalQueryString = "";//对于post请求,固定为字符串""
            string contentType = "application/json";
            //string canonicalHeaders = "content-type:" + contentType + "; charset=utf-8\n" + "host:" + endpoint + "\n";//参与签名的头部信息,至少包含host和content-type两个头部,头部key和value统一转为小写。按照Key:vlaue\n格式拼接;多个头部,按照头部key(小写)的ASCII升序进行拼接
            string canonicalHeaders = "content-type:" + contentType + "\nhost:" + endpoint + "\n";
            string signedHeaders = "content-type;host";//说明此次请求有哪些头部参与了签名
            string hashedRequestPayload = SHA256Hex(requestPayload);//对http请求正文做SHA256哈希,然后十六进制编码,最后编码串转为小写字母
            string canonicalRequest = httpRequestMethod + "\n"
                + canonicalUri + "\n"
                + canonicalQueryString + "\n"
                + canonicalHeaders + "\n"
                + signedHeaders + "\n"
                + hashedRequestPayload;
            Console.WriteLine(" ************* 步骤 1:拼接规范请求串 *************");
            Console.WriteLine(canonicalRequest);

// ************* 步骤 2:拼接待签名字符串 *************
            string credentialScope = datestr + "/" + service + "/" + "tc3_request";
            string hashedCanonicalRequest = SHA256Hex(canonicalRequest);
            string stringToSign = algorithm + "\n" + requestTimestamp.ToString() + "\n" + credentialScope + "\n" + hashedCanonicalRequest;
            Console.WriteLine("************* 步骤 2:拼接待签名字符串 *************");
            Console.WriteLine(stringToSign);

// ************* 步骤 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(" ************* 步骤 3:计算签名 *************");
            Console.WriteLine(signature);

// ************* 步骤 4:拼接 Authorization *************
            string authorization = algorithm + " "
                + "Credential=" + secretid + "/" + credentialScope + ", "
                + "SignedHeaders=" + signedHeaders + ", "
                + "Signature=" + signature;
            Console.WriteLine("************* 步骤 4:拼接 Authorization *************");
            Console.WriteLine(authorization);

Dictionary<string, string> headers = new Dictionary<string, string>();
            headers.Add("Authorization", authorization);
            headers.Add("Host", endpoint);
            headers.Add("Content-Type", contentType);
            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;
        }

修改后,仍然提示鉴权失败的错误,后来再仔细检查post请求,发现request请求有定义ContentType,本身Headers里面有增加,这里删除了request.ContentType = contentType。删除后接口调用成功。 代码如下:

public static string HttpPost(string url, string content, string contentType = "application/json", Encoding charset = null)
        {
            HttpWebRequest request = (HttpWebRequest)HttpWebRequest.Create(url);
            request.Method = "POST";
            //request.ContentType = contentType;
            request.Accept = "*/*";
            request.Timeout = 150000;
            request.ReadWriteTimeout = 150000;
            request.AllowAutoRedirect = false;
            request.Proxy = null;

var dicHeaders = GetSignedString(content);
            foreach (var dic in dicHeaders)
            {
                request.Headers.Add(dic.Key, dic.Value);
            }
            WebResponse response = null;
            string responseStr = null;
            if (charset == null)
            {
                charset = Encoding.UTF8;
            }
            try
            {
                if (string.IsNullOrEmpty(content))
                {
                    request.ContentLength = 0;
                }
                else
                {
                    byte[] data = charset.GetBytes(content.ToString());
                    request.ContentLength = data.Length;
                    using (Stream stream = request.GetRequestStream())
                    {
                        stream.Write(data, 0, data.Length);
                    }
                }

response = request.GetResponse();
                if (response != null)
                {
                    StreamReader reader = new StreamReader(response.GetResponseStream(), charset);
                    responseStr = reader.ReadToEnd();
                    reader.Close();
                }
            }
            catch (Exception ex)
            {
                Console.WriteLine("ex:" + ex.Message);
            }
            finally
            {
                request = null;
                response = null;
            }

return responseStr;
        }

static void Main(string[] args)
        {
            string sessionId = TTSHelper.GetID.ToString();
            string requestPayload = "{\"Text\":\"测试语音合成接口\",\"SessionId\":\""+sessionId+"\",\"Volume\":0,\"Speed\":-1,\"ProjectId\":1,\"ModelType\":1,\"VoiceType\":1008,\"PrimaryLanguage\":1,\"SampleRate\":16000,\"Codec\":\"wav\"}";
            var res= TTSHelper.HttpPost("https://tts.tencentcloudapi.com", requestPayload);
            Console.WriteLine("res:" + res);
        }

腾讯语音合成V3鉴权失败相关推荐

  1. 腾讯云API接口鉴权v3 鉴权失败问题 AuthFailure.SignatureFailure

    最近我开发的CRM项目正好在做营销短信的功能,这个功能需要对接腾讯云的第三方短信接口.众所周知,对接接口最难的就是鉴权部分了,毕竟为了安全嘛.云API鉴权一直是比较晦涩难懂的,建议大家还是去githu ...

  2. 腾讯云----首次登录提示“腾讯云实例鉴权失败,请确认实例已启用密码鉴权并且账号密码正确”

    参考文档:https://blog.csdn.net/chenmozhe22/article/details/103709619 我是对该实例22等用到的端口添加准入,然后关机重置密码之后就可以了.如 ...

  3. 关于feign开启hystrix导致用户鉴权失败

    关于feign开启hystrix熔断导致用户鉴权失败的原因是: feign的hystrix熔断默认机制是线程池隔离.而代码在获取用户权限信息时又是线程池处理,所以导致每次获取用户信息为null. 处理 ...

  4. androidstudio 引入百度或者高德地图 鉴权失败

    问题描述:今天尝试在Android项目中引入地图功能,刚开始尝试了百度地图,获取sha1,填写packageName等操作非常流畅,但是测试的时候,发现地图只显示一堆网格,提示鉴权失败,让去论坛自己查 ...

  5. spring-cloud-gateway GlobalFilter 自定义鉴权失败 返回数据结构

    1. 在使用 spring-cloud-gateway 拦截鉴权的时候的时候,错误一般返回401. 我们该如果自定义自己的返回权限呢.图中红色部分就是自定义鉴权失败返回数据结构. @Configura ...

  6. android 高德地图SDK报 KEY鉴权失败

    android 高德地图SDK报 KEY鉴权失败. 一般在项目被转移,或项目使用的SDK被其他项目使用时,会发生这种情况! 解决办法 进入高德地图api控制台 点应用管理-我的应用-创建应用 - 根据 ...

  7. springboot+shiro前后端分离过程中跨域问题、sessionId问题、302鉴权失败问题

    写在前面:2020年2月29号修改该文章,之前针对302鉴权失败问题的解决方案存在 "WebUtils.toHttp 往返回response写返回值的时候出现回写跨域问题".现已进 ...

  8. 点盾云输入激活码激活视频时,显示鉴权失败无效激活码怎么办?

    如今许多培训机构或者经营网课视频的商家,都会选择使用点盾云视频加密软件来保护自己的视频不被随意传播泄漏传播.那么在使用过程中或多或少会遇到一些不明白的问题,遇到不明白不知道怎样处理的问题应该怎么办呢? ...

  9. apigw鉴权分析(1-2)腾讯开放平台 - 鉴权分析

    一.访问入口 http://wiki.open.qq.com/wiki/%E8%85%BE%E8%AE%AF%E5%BC%80%E6%94%BE%E5%B9%B3%E5%8F%B0%E7%AC%AC% ...

  10. 钉钉开放文档——JSAPI鉴权失败

    钉钉鉴权后路由跳转调用定位(需要鉴权)报错 如下 13:32:28.240 [http-nio-8066-exec-6] INFO c.a.w.c.c.CommonController -[uploa ...

最新文章

  1. 转载:Linux命令之查看文件占用空间大小-du,df
  2. 【NLP】ACL 2021中的25个Transformers模型
  3. boost::mpi模块实现测试mpi版本
  4. 表达式的计算结果必须为节点集 调试
  5. C - Insertion Sort Gym - 101955C(2018icpc沈阳/打表找规律)
  6. 前端学习(2344):打包和部署
  7. 如何查看linux的版本?
  8. 网易的企业免费邮箱和腾讯的企业邮箱
  9. Android小程序白屏,微信小程序web-view跳转h5 安卓白屏
  10. 统计学基础知识之统计思维
  11. 超硬核!数据结构学霸笔记,考试面试吹牛就靠它
  12. android 视频播放器硬解码,万能视频播放器VPlayer:唯一真正硬解码
  13. Max Script|修改器篇
  14. 重庆市计算机考试题库,重庆市计算机一级题库
  15. winxp无法访问服务器共享文件夹,winxp系统无法访问共享文件夹提示网络错误的技巧介绍...
  16. 详谈GoLang的panic和error
  17. 程序员是如何开灯的 白话闲聊mqtt协议
  18. 天时地利人和—一个传奇操作系统的诞生记
  19. 最新教程:java(IDEA,eclipse都有)通过JDBC链接SQLServer2012数据库
  20. chrome浏览器字体小于12px的解决方式

热门文章

  1. python selenium清除缓存_SeleniumPython:无法清除chrome浏览器缓存
  2. 检定证书、校准证书与测试证书的区别
  3. Android设备上px(像素)、dpi(像素密度)、dip(密度无关像素)之间的关系
  4. 无缘无故,谷歌浏览器主页被篡改为360导航,如何解决?
  5. 浏览器首页被360恶意篡改,解决方法
  6. 原生开发、H5开发和混合开发的区别
  7. 我的第一篇博客-Hello World
  8. 查看本机计算机id,win7电脑如何用命令查看本机IP地址
  9. 如何在excel中单独冻结多行或多列
  10. 【Excel 教程系列第 1 篇】删除所有空白行,隐藏空白行