直接上代码:
import Foundation
import CryptoKit
extension String {
func SHA256() -> String {
CryptoKit.SHA256.hash(data: self.data(using: .utf8)!)
.compactMap { String(format: "%02x", $0) }
.joined()
}
func HMAC_SHA256(_ key: String) -> HMAC<CryptoKit.SHA256>.MAC {
HMAC<CryptoKit.SHA256>.authenticationCode(
for : Data(self.utf8),
using : SymmetricKey(data: Data(key.utf8)))
}
func HMAC_SHA256(_ key: HMAC<CryptoKit.SHA256>.MAC) -> HMAC<CryptoKit.SHA256>.MAC {
HMAC<CryptoKit.SHA256>.authenticationCode(
for : Data(self.utf8),
using : SymmetricKey(data:key))
}
}
extension HMAC<CryptoKit.SHA256>.MAC {
func toString() -> String {
self.compactMap { String(format: "%02x", $0) }
.joined()
}
}
struct TencentSecret {
var secretId : String
var secretKey : String
}
class TencentCloudRequest {
enum Method : String {
case GET = "GET"
case POST = "POST"
}
enum TencentCloudRequestError : Error {
case RequestError(code:Int, data :String)
}
var headers : [String: String] = [:]
var tencentSecret : TencentSecret
var host : String
var service : String
var action : String
var region : String
var method : Method
var payLoad : String
var version : String
var contentType : String
var date : String = String(Date().formatted(.iso8601.year().month().day().dateSeparator(.dash)))
var timestamp : String = "\(Int(Date().timeIntervalSince1970))"
init(secret : TencentSecret ,
host :String,
service :String,
action :String,
region :String = "",
method :Method = Method.POST,
payload :String = "{}",
version :String = "2020-03-24",
contentType :String = "application/json"
) {
self.tencentSecret = secret
self.host = host
self.service = service
self.action = action
self.region = region
self.method = method
self.payLoad = payload
self.version = version
self.contentType = contentType
self.headers["Host"] = self.host
self.headers["Content-Type"] = self.contentType
self.headers["X-TC-Timestamp"] = self.timestamp
self.headers["X-TC-Version"] = self.version
self.headers["X-TC-Action"] = self.action
if self.region != "" {
self.headers["X-TC-Region"] = self.region
}
}
}
extension TencentCloudRequest {
func sign() {
var canonicalRequest = ""
canonicalRequest.append(self.method.rawValue + "\n" )
canonicalRequest.append("/\n" )
canonicalRequest.append("\n")
canonicalRequest.append("content-type:\(self.contentType)\nhost:\(self.host)\nx-tc-action:\(self.action.lowercased())\n" + "\n" )
canonicalRequest.append("content-type;host;x-tc-action" + "\n" )
canonicalRequest.append(self.payLoad.SHA256())
var stringToSign = ""
stringToSign.append("TC3-HMAC-SHA256" + "\n")
stringToSign.append(self.timestamp + "\n")
stringToSign.append("\(self.date)/\(self.service)/tc3_request" + "\n")
stringToSign.append(canonicalRequest.SHA256())
let secretDate = self.date.HMAC_SHA256("TC3" + self.tencentSecret.secretKey)
let secretService = self.service.HMAC_SHA256(secretDate)
let secretSigning = "tc3_request".HMAC_SHA256(secretService)
let signature = stringToSign.HMAC_SHA256(secretSigning).toString()
var authorization = ""
authorization.append("TC3-HMAC-SHA256" + " ")
authorization.append("Credential=" + self.tencentSecret.secretId + "/" + "\(self.date)/\(self.service)/tc3_request" + ", ")
authorization.append("SignedHeaders=" + "content-type;host;x-tc-action" + ", " )
authorization.append("Signature=" + signature)
self.headers["Authorization"] = authorization
}
}
extension TencentCloudRequest {
func request() async throws -> Data {
self.sign()
let url : URL = URL(string: "https://\(self.headers["Host"]!)")!
var request = URLRequest(url: url)
request.httpMethod = self.method.rawValue
self.headers.forEach { (key: String, value: String) in
request.addValue(value, forHTTPHeaderField: key)
}
request.httpBody = self.payLoad.data(using: .utf8)
let (data, response) = try await URLSession.shared.data(for: request)
if let resp = response as? HTTPURLResponse {
if resp.statusCode != 200 {
throw TencentCloudRequestError.RequestError(code: resp.statusCode, data: String(data: data, encoding: String.Encoding.utf8)!)
}
}
return data
}
}
使用:
let request = TencentCloudRequest(
secret: TencentSecret(secretId: "<secretId>",
secretKey: "<secretKey>"),
host: "lighthouse.tencentcloudapi.com",
service: "lighthouse",
action: "DescribeRegions"
)
Task {
let res = try? await request.request()
print(String(data: res!, encoding: .utf8)!)
}