V3手动鉴权失败之Nodejs篇

2020-12-11 15:49:10 浏览数 (1)

导语

该系列其他篇章:

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 示例 。 

  /**
   * 详细文档需要参考 :
   * 1. 请求结构:https://cloud.tencent.com/document/product/866/33517
   * 2. 公共参数:https://cloud.tencent.com/document/product/866/33518
   * 3. 接口鉴权v3:https://cloud.tencent.com/document/product/866/33519
   * 4. 文字识别产品介绍文档:https://cloud.tencent.com/document/product/866/37490
   */

  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/jsonnhost:ocr.tencentcloudapi.comn";
  /**
   * 参与签名的头部信息,content-type 和 host 为必选头部,
   * 其中 host 指接口请求域名 POST 请求支持的 Content-Type 类型有:
   * 1. application/json(推荐),必须使用 TC3-HMAC-SHA256 签名方法。; 
   * 2. application/x-www-form-urlencoded,必须使用 HmacSHA1 或 HmacSHA256 签名方法。; 
   * 3. multipart/form-data(仅部分接口支持),必须使用 TC3-HMAC-SHA256 签名方法。
   */
  var SignedHeaders = "content-type;host";
  /**
   * 参与签名的头部信息的 key,可以说明此次请求都有哪些头部参与了签名,和 CanonicalHeaders 包含的头部内容是一一对应的。
   * content-type 和 host 为必选头部 。 
   * 注意: 
   * 1. 头部 key 统一转成小写; 
   * 2. 多个头部 key(小写)按照 ASCII 升序进行拼接,并且以分号(;)分隔 。 
   */
  // 传入需要做 HTTP 请求的正文 body
  var payload = {
      "ImageUrl":"https://img.yuanmabao.com/zijie/pic/2020/12/11/clj0kay0ob3.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示例,欢迎大家持续关注~

0 人点赞