导语
该系列其他篇章:
V3手动鉴权失败之Nodejs篇
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接口为例,详叙Go语言
demo。
前期准备
Go语言环境:直接在Go官网根据操作系统类型下载并安装指定安装包即可。
SecrectId和SecretKey:接口鉴权的密钥。可以把SecretId理解成“账号”,把SecretKey理解成“密码”。在自己的腾讯云官网控制台获取:访问管理 -> 访问密钥 -> API密钥管理。
手动鉴权相关文档:请求结构、公共参数、V3接口鉴权
具体代码
运行go语言代码,即可完成v3鉴权,并发送http请求,收到具体的response响应。运行指令为:
代码语言:javascript复制go run go_v3.go
具体的go_v3.go代码如下,只需要简单复制,然后输入自己的SecretId和SecretKey两个字段即可:
代码语言:javascript复制package main
import (
"bytes"
"crypto/hmac"
"crypto/sha256"
"fmt"
"io/ioutil"
"net/http"
"strconv"
"time"
)
const SecretId = "xxx";//填入自己的secretId
const SecretKey = "xxx";//填入自己的secretKey
//算法
const Algo = "sha256"
const Url = "https://iai.tencentcloudapi.com"
//规范请求串
const HTTPRequestMethod = "POST"
const CanonicalURI = "/"
const CanonicalQueryString = ""
const CanonicalHeaders = "content-type:application/json; charset=utf-8nhost:iai.tencentcloudapi.comn"
const SignedHeaders = "content-type;host"//参与签名的头部信息
//签名字符串
const Algorithm = "TC3-HMAC-SHA256"
const Service = "iai"
const Stop = "tc3_request"
func main() {
var face face
d := face.Authentication("DetectFace",`{"Url":"https://img.yuanmabao.com/zijie/pic/2020/12/11/15zlb3gjeqk.jpg"}`, "2018-03-01")
println(d)
}
type face struct {
}
//鉴权提交
// action 访问方法
// param json参数
// version 版本
func (f *face) Authentication(action string, param string, version string) string {
//loc, _ := time.LoadLocation("")
//fmt.Println(loc, err)
//时间戳
timeNow := time.Now()
//本地时区秒数
timeStampInt := timeNow.Unix()
timeStamp := strconv.FormatInt(timeStampInt, 10)
//UTC时区年月日
nowDate := time.Unix(timeStampInt,0).UTC().Format("2006-01-02")
//加密参数
hashedRequestPayload := f.HashEncryption(param)
//初次加密 规范请求串
canonicalRequest := HTTPRequestMethod "n"
CanonicalURI "n"
CanonicalQueryString "n"
CanonicalHeaders "n"
SignedHeaders "n"
hashedRequestPayload;
fmt.Println(canonicalRequest)
//第二次加密 签名字符串
credentialScope := nowDate "/" Service "/" Stop;
hashedCanonicalRequest := f.HashEncryption(canonicalRequest);
stringToSign := Algorithm "n"
timeStamp "n"
credentialScope "n"
hashedCanonicalRequest
fmt.Println(stringToSign)
//计算签名
secretDate := f.HashHmacSha256Encryption(nowDate, "TC3" SecretKey, true)
secretService := f.HashHmacSha256Encryption(Service, secretDate, true)
secretSigning := f.HashHmacSha256Encryption(Stop, secretService, true)
//签名
signature := f.HashHmacSha256Encryption(stringToSign, secretSigning, false)
authorization := Algorithm " "
"Credential=" SecretId "/" credentialScope ", "
"SignedHeaders=" SignedHeaders ", "
"Signature=" signature
fmt.Println(authorization)
//申明header头部
var header = map[string]string{
"Content-Type" : "application/json; charset=utf-8",
"Authorization" : authorization,
"Host" : "iai.tencentcloudapi.com",
"X-TC-Action" : action,
"X-TC-Version" : version,
"X-TC-Timestamp" : timeStamp,
}
return f.http_post_request(header, param)
}
//256 加密算法 转小写
func (f *face) HashEncryption(sign string) string{
sha256Byte := sha256.Sum256([]byte(sign))
tf16 := fmt.Sprintf("%x", sha256Byte)
return tf16
}
//Hash_Hmac 加密算法
//sign 加密字符串
//key 加密key
//flag true 原始数据 false 小写16进制数据
func (f *face) HashHmacSha256Encryption(sign string, key string, flag bool) string {
hash := hmac.New(sha256.New,[]byte(key)) // 创建对应的sha256哈希加密算法
hash.Write([]byte(sign)) // 写入加密数据
if flag {
return string(hash.Sum(nil))
}
return fmt.Sprintf("%x",hash.Sum(nil))
}
func (f *face) http_post_request(header map[string]string, param string) string {
client := &http.Client{}
req_new := bytes.NewBuffer([]byte(param))
req, err := http.NewRequest("POST", Url, req_new)
//设置header头部
for k,v := range header{
req.Header.Set(k, v)
}
//发送请求
resp, err := client.Do(req)
//延迟执行断开
defer resp.Body.Close()
body, err := ioutil.ReadAll(resp.Body)
if err != nil {
fmt.Println("post request error : ", err)
return "error"
}
return string(body)
}