V3手动鉴权失败之Nodejs篇

导语

该系列其他篇章:

V3手动鉴权失败之Go篇

V3手动鉴权失败之Python篇

V3手动鉴权失败之Java篇

V3手动鉴权失败之PHP篇

V3手动鉴权失败之C#篇

腾讯云 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接口为例,详叙Nodejs语言demo。

前期准备

node环境:直接在node官网根据操作系统类型下载并安装指定安装包即可。

SecrectId和SecretKey:接口鉴权的密钥。可以把SecretId理解成“账号”,把SecretKey理解成“密码”。在自己的腾讯云官网控制台获取:访问管理 -> 访问密钥 -> API密钥管理。

手动鉴权相关文档:请求结构、公共参数、V3接口鉴权

具体代码

为了模拟具体的http请求,需要安装request包:

代码语言:javascript
复制
npm i request

运行nodejs代码,可以完成v3鉴权,并发送http请求,收到具体的response响应。运行指令为:

代码语言:javascript
复制
node nodev3.js

具体的nodev3js代码如下,只需要简单复制,然后输入自己的SecretId和SecretKey两个字段即可:

代码语言:javascript
复制
  // 本示例为V3接口鉴权之Node.js篇,以POST请求GeneralBasicOCR接口为例
  // GET 请求的请求包大小不得超过 32KB。
  // POST 请求使用签名方法为 HmacSHA1、HmacSHA256 时不得超过1MB 。
  // POST 请求使用签名方法为 TC3-HMAC-SHA256 时支持 10MB。 这里使用 POST 示例 。

/**

const crypto = require('crypto')
var request = require("request")

var SecretId = ""; // // SecretId, 需要替换为自己的
var SecretKey = ""; // SecretKey, 需要替换为自己的
// const proxyUrl = '' // 如果公司需要通过代理才能访问外网,可以在此设置请求代理

// 1. 拼接规范请求串 CanonicalRequest
var HTTPRequestMethod = 'POST'; // HTTP 请求方法(GET、POST )。此示例取值为 POST
var CanonicalURI = '/'; // URI 参数,API 3.0 固定为正斜杠(/)
var CanonicalQueryString = ""; // POST请求时为空
var CanonicalHeaders = "content-type:application/json\nhost:ocr.tencentcloudapi.com\n";
/**

  • 参与签名的头部信息,content-type 和 host 为必选头部,
  • 其中 host 指接口请求域名 POST 请求支持的 Content-Type 类型有:
    1. application/json(推荐),必须使用 TC3-HMAC-SHA256 签名方法。;
    1. application/x-www-form-urlencoded,必须使用 HmacSHA1 或 HmacSHA256 签名方法。;
    1. multipart/form-data(仅部分接口支持),必须使用 TC3-HMAC-SHA256 签名方法。
      /
      var SignedHeaders = "content-type;host";
      /
      *
  • 参与签名的头部信息的 key,可以说明此次请求都有哪些头部参与了签名,和 CanonicalHeaders 包含的头部内容是一一对应的。
  • content-type 和 host 为必选头部 。
  • 注意:
    1. 头部 key 统一转成小写;
    1. 多个头部 key(小写)按照 ASCII 升序进行拼接,并且以分号(;)分隔 。
      */
      // 传入需要做 HTTP 请求的正文 body
      var payload = {
      "ImageUrl":"https://imgcache.qq.com/open_proj/proj_qcloud_v2/gateway/product/ocr-demo/css/img/GeneralBasicOCR1.jpg",
      "LanguageType":"auto" // 语言类型,可选,此处我用的是 auto 即自动
      }
      var HashedRequestPayload = crypto.createHash('sha256').update(JSON.stringify(payload)).digest('hex'); // 哈希加密后的请求字符串 此示例结果是e4b76b87ed3234a73c7ff4665a4e9d566b7f9c959bc616a0b6aec403789a5924
      console.log(HashedRequestPayload)
      // 拼接
      var CanonicalRequest = HTTPRequestMethod + '\n' +
      CanonicalURI + '\n' +
      CanonicalQueryString + '\n' +
      CanonicalHeaders + '\n' +
      SignedHeaders + '\n' +
      HashedRequestPayload;
      console.log('1. 拼接规范请求串' + CanonicalRequest);
      console.log('\n');

// 2. 拼接待签名字符串
var Algorithm = "TC3-HMAC-SHA256"; // 签名算法,目前固定为 TC3-HMAC-SHA256
var RequestTimestamp = Math.round(new Date().getTime()/1000) + ""; // 请求时间戳,即请求头部的公共参数 X-TC-Timestamp 取值,取当前时间 UNIX 时间戳,精确到秒
var t = new Date();
var date = t.toISOString().substr(0, 10); // 计算 Date 日期 date = "2019-08-26"
/**

  • Date 必须从时间戳 X-TC-Timestamp 计算得到,且时区为 UTC+0。
  • 如果加入系统本地时区信息,例如东八区,将导致白天和晚上调用成功,但是凌晨时调用必定失败。
  • 假设时间戳为 1551113065,在东八区的时间是 2019-02-26 00:44:25,但是计算得到的 Date 取 UTC+0 的日期应为 2019-02-25,而不是 2019-02-26。
  • Timestamp 必须是当前系统时间,且需确保系统时间和标准时间是同步的,如果相差超过五分钟则必定失败。
  • 如果长时间不和标准时间同步,可能导致运行一段时间后,请求必定失败,返回签名过期错误。
    /
    var CredentialScope = date + "/ocr/tc3_request";
    /
    *
  • 拼接 CredentialScope 凭证范围,格式为 Date/service/tc3_request ,
  • service 为服务名,慧眼用 faceid , OCR 文字识别用 ocr
    */

// 将第一步拼接得到的 CanonicalRequest 再次进行哈希加密
var HashedCanonicalRequest = crypto.createHash('sha256').update(CanonicalRequest).digest('hex');
// 拼接
var StringToSign = Algorithm + '\n' +
RequestTimestamp + '\n' +
CredentialScope + '\n' +
HashedCanonicalRequest;
console.log('2. 拼接待签名字符串' + StringToSign);
console.log('\n');

// 3. 计算签名
var SecretDate = crypto.createHmac('sha256', "TC3"+SecretKey).update(date).digest();
var SecretService = crypto.createHmac('sha256', SecretDate).update("ocr").digest();
var SecretSigning = crypto.createHmac('sha256', SecretService).update("tc3_request").digest();
var Signature = crypto.createHmac('sha256', SecretSigning).update(StringToSign).digest('hex');
console.log('3. 计算签名' + Signature);

// 4. 拼接Authorization
var Algorithm = "TC3-HMAC-SHA256";
var Authorization =
Algorithm + ' ' +
'Credential=' + SecretId + '/' + CredentialScope + ', ' +
'SignedHeaders=' + SignedHeaders + ', ' +
'Signature=' + Signature
console.log('4. 拼接Authorization' + Authorization)

// 5.发送POST请求
console.log(RequestTimestamp)
// https模块 request options配置
var options = {
url: 'https://ocr.tencentcloudapi.com/',
method:'POST',
json: true,
//proxy: proxyUrl,
headers: {
"Content-Type": "application/json",
"Authorization": Authorization,
"Host": "ocr.tencentcloudapi.com",
"X-TC-Action": "GeneralBasicOCR",
"X-TC-Version": "2018-11-19",
"X-TC-Timestamp": RequestTimestamp,
"X-TC-Region": "ap-guangzhou"
},
body: payload,
};
// 发起请求
request(options, function (error, response, body) {
if (error) throw new Error(error);
console.log(JSON.stringify(body))
});

总结

本文以NodeJS语言为例,同步了一个可以直接执行的手动鉴权和请求发送代码demo,后续会逐步讲解其他语言(Python Java Go PHP .Net)的demo示例,欢迎大家持续关注~