1、能够解决的问题
虽然腾讯云已经提供了支持多种语言的 SDK,使用起来也非常方便,但是某些环境中没有相关的运行环境使用起来往往带来一些环境准备和合规的成本。PowerShell 作为Windows环境普遍存在脚本环境,如果能够顺利运行云相关API将会非常方便。
2、存在的困难
原生API相关签名算法的实现会劝退很多人,在研究一番后成功解决了遇到的编码等问题。
3、代码实现
话不多说,贴代码(这里以调用 VPC查询安全组为例)。
代码语言:text复制# 首先通过以下代码实现 HTTPS 访问
add-type @"
using System.Net;
using System.Security.Cryptography.X509Certificates;
public class TrustAllCertsPolicy : ICertificatePolicy {
public bool CheckValidationResult(
ServicePoint srvPoint, X509Certificate certificate,
WebRequest request, int certificateProblem) {
return true;
}
}
"@
[System.Net.ServicePointManager]::CertificatePolicy = New-Object TrustAllCertsPolicy
# 密钥参数
$secret_id = "IKID8****************dBUU1CC0CIJ"
$secret_key = "dBUU1CC0CIJ****************IKID8"
#HMAC_Sha256 算法
function hmacsha256 () {
param (
$key,
$message
)
$hmacsha = New-Object System.Security.Cryptography.HMACSHA256
#$hmacsha.key = [Text.Encoding]::ASCII.GetBytes($key)
$hmacsha.key = $key
return($hmacsha.ComputeHash([Text.Encoding]::UTF8.GetBytes($message)))
}
#Sha256 Hash 算法
function hashsha256{
param(
[string]$message
)
$utf8 = New-Object -TypeName System.Text.UTF8Encoding
$hasher = [System.Security.Cryptography.HashAlgorithm]::Create("SHA256")
$hash = $hasher.ComputeHash($utf8.GetBytes($message))
# {0:X}转换为16进制大写,{0:x}转16进制小写,{0:x8}指定所需进制位数
return(-join ($hash |foreach {"{0:x}" -f $_}))
}
$UTCDate = (get-date).ToUniversalTime()
$dateTime = Get-Date -Date $UTCDate -Format "yyyy-MM-dd"
$timeStamp = [int](Get-Date -Date $UTCDate -UFormat %s)
$service = "vpc"
$APIHost = "vpc.tencentcloudapi.com"
$endpoint = "https://" $APIHost
$region = "ap-hongkong"
$action = "DescribeSecurityGroupPolicies"
$version = "2017-03-12"
$algorithm = "TC3-HMAC-SHA256"
$params = @{
"SecurityGroupId" = "sg-jxxxx7"
}
# ************* 步骤 1:拼接规范请求串 *************
$http_request_method = "POST"
#URI 参数,API 3.0 固定为正斜杠(/)
$canonical_uri = "/"
#发起 HTTP 请求 URL 中的查询字符串,对于 POST 请求,固定为空字符串"",对于 GET 请求,则为 URL 中问号(?)后面的字符串内容,例如:Limit=10&Offset=0。
$canonical_querystring = ""
$ct = "application/json; charset=utf-8"
$payload = '{"SecurityGroupId": "sg-j****7"}'
<###
参与签名的头部信息,至少包含 host 和 content-type 两个头部,也可加入自定义的头部参与签名以提高自身请求的唯一性和安全性。
拼接规则:
1、头部 key 和 value 统一转成小写,并去掉首尾空格,按照 key:valuen 格式拼接;
2、多个头部,按照头部 key(小写)的 ASCII 升序进行拼接。
#>
$canonical_headers = "content-type:$ct`nhost:$APIHost`n"
#参与签名的头部信息,说明此次请求有哪些头部参与了签名,和 CanonicalHeaders 包含的头部内容是一一对应的。content-type 和 host 为必选头部。
$signed_headers = "content-type;host"
#即对 HTTP 请求正文做 SHA256 哈希,然后十六进制编码,最后编码串转换成小写字母 hashlib.sha256(payload.encode("utf-8")).hexdigest()。对于 GET 请求,RequestPayload 固定为空字符串 。
$hashed_request_payload = hashsha256($payload)
#组装规范请求串
$canonical_request = ($http_request_method "`n"
$canonical_uri "`n"
$canonical_querystring "`n"
$canonical_headers "`n"
$signed_headers "`n"
$hashed_request_payload)
# ************* 步骤 2:拼接待签名字符串 *************
$credential_scope = $dateTime "/" $service "/" "tc3_request"
$hashed_canonical_request = hashsha256($canonical_request)
#Algorithm: 签名算法;timeStamp: Unix时间戳;credential_scope:凭证范围,格式为 Date/service/tc3_request;hashed_canonical_request:步骤1的规范请求串hash值。
$string_to_sign = ($algorithm "`n"
$timeStamp "`n"
$credential_scope "`n"
$hashed_canonical_request)
# ************* 步骤 3:计算签名 *************
# 计算签名摘要函数
$secret_date = hmacsha256 -key ([Text.Encoding]::UTF8.GetBytes("TC3$secret_key")) -message ($dateTime)
#$convertInd32 = $secret_date |% {[convert]::ToInt32($_)}
$secret_service = hmacsha256 -key $secret_date -message $service
$secret_signing = hmacsha256 -key $secret_service -message "tc3_request"
$signature = hmacsha256 -key $secret_signing -message $string_to_sign
$signature = -join ($signature |foreach {"{0:x}" -f $_})
# ************* 步骤 4:拼接 Authorization *************
$authorization = ($algorithm " "
"Credential=" $secret_id "/" $credential_scope ", "
"SignedHeaders=" $signed_headers ", "
"Signature=" $signature)
Write-Host($authorization)
$requestHeder = @{
"Authorization" = $authorization
"Content-Type" = "application/json; charset=utf-8"
"Host" = $APIHost
"X-TC-Action" = $action
"X-TC-Timestamp" = ($timestamp).ToString()
"X-TC-Version" = $version
"X-TC-Region" = $region
}
$test = Invoke-WebRequest -Method Post -Uri $endpoint -Headers $requestHeder -Body $payload -UseBasicParsing
$test.Content
4、创作声明
原创不易,转发引用请注明出处。
作者:cloudmanager@foxmail.com