使用說明
Log ServiceSDK封裝了Log Service的所有API介面,您可以通過Log ServiceSDK方便地調用Log Service的所有API介面。Log ServiceSDK支援自動簽名,並支援多語言版本。推薦使用Log ServiceSDK訪問Log Service,更多資訊,請參見Log ServiceSDK。
為API請求產生簽名,需使用一對存取金鑰。您可以使用已經存在的存取金鑰對,也可以建立新的存取金鑰對,但需要保證使用的金鑰組為啟用狀態。
下文介紹Log Service請求組成結構、演算法流程,並給出各語言簽名演算法的範例程式碼。
請求組成結構
合法的Log Service請求需要在HTTP要求標頭內寫入如下索引值對(大小寫敏感):
欄位名 | 說明 | 樣本 |
x-log-signaturemethod | 請求的加密方式。 | hmac-sha1 |
x-log-apiversion | 訪問的API版本。 | 0.6.0 |
Date | HTTP請求中的標準時間戳記頭,其遵循RFC822/RFC1123格式,格式化字串為%a, %d %b %Y %H:%M:%S GMT ,時區為GMT標準時間。 | Mon, 3 Jan 2010 08:33:47 GMT |
Content-MD5 | HTTP請求中Body部分的MD5值,必須轉換成十六進位大寫英文字母字串。 | 72A15D7DE7EE9E7BB86461FFEA9499 |
Authorization | 簽名,內容格式為LOG accessKeyId:Signature 。其中 accessKeyId為您的AccessKey密鑰ID,Signature 為下文計算得到的簽名字串,請參見簽名演算法流程。 | LOG testAccessKeyId:RLETq4u7sWb3cssZIhsun**** |
Content-Type | 請求中Body部分的類型。若無 Body,可省略此欄位。 | application/json |
完成簽名後的HTTP請求樣本如下所示:
POST /logstores/test-logstore/shards/0?action=split HTTP/1.1
Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
Date: Tue, 23 Aug 2022 12:12:03 GMT
x-log-apiversion: 0.6.0
x-log-signaturemethod: hmac-sha1
Content-Length: 18
Content-Type: application/json
Content-MD5: 49DFDD54B01CBCD2D2AB5E9E5EE6B9B9
Authorization: LOG testAccessKeyId:RLETq4u7sWb3cssZIhsun****
{"hello": "world"}
簽名演算法流程
簽名結構中最為重要的部分是Authorization
欄位,其格式為LOG accessKeyId:Signature
,由使用者密鑰 AccessKeyId
與簽名字串Signature
拼接得到。這裡介紹簽名字串Signature
的構建過程。
簽名訊息體message
簽名字串Signature由簽名訊息體message加密編碼得到,簽名訊息體message的構建過程如下:
名稱 | 內容與格式 | 樣本 |
method | HTTP要求方法,全大寫英文。取值包括GET、POST、PUT和DELETE。 | GET |
Content-MD5 | HTTP請求訊息Body的MD5雜湊值,轉換為十六進位大寫英文字串。若Body為空白,此項為空白字串。 | 49DFDD54B01CBCD2D2AB5E9E5EE6B9B9 |
Content-Type | HTTP請求中Body部分的類型。若Body為空白,此項可為空白字串。 | application/json |
Date | 目前時間的格式化字串。格式為RFC822/RFC1123,格式化字串為%a, %d %b %Y %H:%M:%S GMT ,時區為GMT標準時間。 | Mon, 3 Jan 2010 08:33:47 GMT |
header | header中以 x-log- 或x-acs- 為首碼的索引值對,按 key升序排序後,以 : 串連索引值,以分行符號分隔索引值對。 | |
uri | 請求的路徑,不包括網域名稱與請求參數部分。 | /logstores/test-logstore |
query參數 | 請求的查詢參數,按key升序排序後,以= 串連索引值,以& 分隔索引值對。 | offset=1&size=10 |
完整的message如下所示,注意除最後一行外,每行行末都存在一個分行符號。
POST
1572A15D7DE7EE9E7BB86461FFEA9499
application/json
Tue, 23 Aug 2022 12:12:03 GMT
x-log-apiversion:0.6.0
x-log-bodyrawsize:0
x-log-signaturemethod:hmac-sha1
/logstores?offset=1&size=10
簽名字串Signature
簽名字串Signature的擷取流程如下:
擷取簽名訊息體message。
將message訊息體使用hmac-sha1演算法加密,密鑰為AccessKeySecret,擷取加密後的雜湊值。
將雜湊值使用標準base64進行編碼,獲得簽名字串Signature。
請求籤名過程樣本
為了協助您更好地理解整個請求籤名的流程,我們用兩個樣本來示範整個過程。首先,假設您用做Log ServiceAPI簽名的存取金鑰對如下:
AccessKeyId = "bq2sjzesjmo86kq****"
AccessKeySecret = "4fdO2fTDDnZPU/L7CHNd****"
樣本一
您需要發送如下GET請求列出ali-test-project專案下的所有Logstore,其待簽名的HTTP請求如下:
GET /logstores?logstoreName=&offset=0&size=1000 HTTP/1.1
Date: Mon, 09 Nov 2015 06:11:16 GMT
Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
x-log-apiversion: 0.6.0
x-log-bodyrawsize:0
x-log-signaturemethod: hmac-sha1
如上API請求產生的簽名訊息體為:
GET
Mon, 09 Nov 2015 06:11:16 GMT
x-log-apiversion:0.6.0
x-log-bodyrawsize:0
x-log-signaturemethod:hmac-sha1
/logstores?logstoreName=&offset=0&size=1000
由於是GET請求,該請求無任何HTTP Body,所以產生的簽名字串中Content-Type與Content-MD5域為空白字串。如果以前面指定的AccessKeySecret做簽名運算後得到的簽名Signature為:
jEYOTCJs2e88o+y5F4/S5I****
最後發送經數位簽章的HTTP請求內容如下:
GET /logstores?logstoreName=&offset=0&size=1000 HTTP/1.1
Date:Mon, 09 Nov 2015 06:11:16 GMT
Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
x-log-apiversion: 0.6.0
x-log-bodyrawsize:0
x-log-signaturemethod: hmac-sha1
Authorization: LOG bq2sjzesjmo86kq35behupbq:jEYOTCJs2e88o+y5F4/S5I****
樣本二
您需要給ali-test-project專案中名為test-logstore的Logstore寫入下面的日誌:
topic=""
time=1447048976
source="10.10.10.1"
"TestKey": "TestContent"
為此,按照API定義需要構建如下HTTP請求:
POST /logstores/test-logstore HTTP/1.1
Date: Mon, 09 Nov 2015 06:03:03 GMT
Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
x-log-apiversion:0.6.0
x-log-bodyrawsize:50
x-log-signaturemethod:hmac-sha1
Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
Content-Length: 52
<日誌內容序列化成ProtoBuffer格式的位元組流>
在這個HTTP請求中,寫入的日誌內容首先被序列化成ProtoBuffer格式(請參見資料編碼方式瞭解該格式的更多細節)後作為請求Body。所以該請求的Content-Type頭的值指定為application/x-protobuf。類似,Content-MD5頭的值是請求body對應的MD5值。按照上面的簽名字串構造方式,這個請求對應的簽名訊息體為:
POST
1DD45FA4A70A9300CC9FE7305AF2C494
application/x-protobuf
Mon, 09 Nov 2015 06:03:03 GMT
x-log-apiversion:0.6.0
x-log-bodyrawsize:50
x-log-compresstype:lz4
x-log-signaturemethod:hmac-sha1
/logstores/ali-test-logstore
同樣,以前面樣本中的AccessKeySecret做簽名運算,得到的最終簽名為:
XWLGYHGg2F2hcfxWxMLiNk****
最後發送經數位簽章的HTTP請求內容如下:
POST /logstores/ali-test-logstore HTTP/1.1
Date: Mon, 09 Nov 2015 06:03:03 GMT
Host: ali-test-project.cn-hangzhou.log.aliyuncs.com
x-log-apiversion:0.6.0
x-log-bodyrawsize:50
x-log-compresstype:lz4
x-log-signaturemethod:hmac-sha1
Content-MD5: 1DD45FA4A70A9300CC9FE7305AF2C494
Content-Length: 52
Authorization: LOG bq2sjzesjmo86kq35behupbq:XWLGYHGg2F2hcfxWxMLiNk****
<日誌內容序列化成ProtoBuffer格式的位元組流>
程式碼範例
Java簽名範例程式碼
該樣本依賴第三方庫commons-codec
,請在pom.xml
下添加Maven依賴:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
以下為請求籤名的程式碼範例,僅為參考:
package com.aliyun.openservices.log.http.signer;
import org.apache.commons.codec.binary.Base64;
import javax.crypto.Mac;
import javax.crypto.spec.SecretKeySpec;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;
import java.security.MessageDigest;
import java.text.DateFormat;
import java.text.SimpleDateFormat;
import java.util.*;
import java.util.stream.Collectors;
public class v1 {
public static String md5(byte[] bs) throws Exception {
MessageDigest digest = MessageDigest.getInstance("MD5");
digest.update(bs);
String hex = new BigInteger(1, digest.digest()).toString(16).toUpperCase();
return new String(new char[32 - hex.length()]).replace("\0", "0") + hex;
}
public static String getDateString() {
DateFormat df = new SimpleDateFormat("EEE, dd MMM yyyy HH:mm:ss z", Locale.US);
df.setTimeZone(new SimpleTimeZone(0, "GMT"));
return df.format(new Date());
}
public static void sign(String method, String uri, String accessKeyId, String accessKeySecret,
Map<String, String> params,
Map<String, String> headers,
byte[] body) throws Exception {
int contentLength = 0;
String contentMD5 = "", message = "";
headers.put("x-log-apiversion", "0.6.0");
headers.put("x-log-signaturemethod", "hmac-sha1");
if (body != null && body.length > 0) {
contentLength = body.length;
contentMD5 = md5(body);
headers.put("Content-MD5", contentMD5);
}
String date = getDateString();
headers.put("Date", date);
headers.put("Content-Length", String.valueOf(contentLength));
message += method + "\n"
+ contentMD5 + "\n"
+ headers.getOrDefault("Content-Type", "") + "\n"
+ date + "\n";
// header
String headerStr = headers.entrySet().stream()
.filter(e -> e.getKey().startsWith("x-log-") || e.getKey().startsWith("x-acs-"))
.sorted(Map.Entry.comparingByKey())
.map(e -> String.format("%s:%s\n", e.getKey(), e.getValue()))
.collect(Collectors.joining(""));
message += headerStr;
// uri & params
message += uri;
if (params.size() > 0) {
message += "?";
}
message += params.entrySet().stream()
.sorted(Map.Entry.comparingByKey())
.map(e -> String.format("%s=%s", e.getKey(), e.getValue()))
.collect(Collectors.joining("&"));
// signature & authorization
Mac mac = Mac.getInstance("HmacSHA1");
mac.init(new SecretKeySpec(accessKeySecret.getBytes(StandardCharsets.UTF_8), "HmacSHA1"));
String signature = new String(Base64.encodeBase64(mac.doFinal(message.getBytes(StandardCharsets.UTF_8))));
String auth = "LOG " + accessKeyId + ":" + signature;
headers.put("Authorization", auth);
}
}
Python簽名範例程式碼
以下為請求籤名的程式碼範例,僅為參考:
import base64
import hashlib
import hmac
import locale
from datetime import datetime
from typing import Dict, Tuple
def get_date():
try:
locale.setlocale(locale.LC_TIME, "C")
except Exception as ex:
pass
return datetime.utcnow().strftime('%a, %d %b %Y %H:%M:%S GMT')
def sign(method: str, uri: str, access_key_id: str,
access_key_secret: str, params: Dict[str, str],
headers: Dict[str, str], body: bytes):
content_length = 0
content_md5, message = '', ''
headers["x-log-apiversion"] = "0.6.0"
headers["x-log-signaturemethod"] = "hmac-sha1"
if body is not None and len(body) > 0:
content_length = str(len(body))
content_md5 = hashlib.md5(body).hexdigest().upper()
headers['Content-MD5'] = content_md5
date = get_date()
headers['Date'] = date
headers['Content-Length'] = content_length
content_type = headers.get('Content-Type', '')
message += method + "\n" + content_md5 + \
"\n" + content_type + "\n" + date + "\n"
# header
filter_by_prefix = lambda t: t[0].startswith('x-log-') or t[0].startswith('x-acs-')
slsHeaders = list(filter(filter_by_prefix, headers.items()))
sort_by_key = lambda k: k[0]
for [k, v] in sorted(slsHeaders, key=sort_by_key):
message += k + ':' + v + "\n"
# uri and params
message += uri
message += '?' if len(params) > 0 else ''
sep = ''
for [k, v] in sorted(params.items(), key=sort_by_key):
message += sep + k + '=' + v
sep = '&'
# signature and authorization
hashed = hmac.new(access_key_secret.encode('utf8'),
message.encode('utf8'), hashlib.sha1).digest()
signature = base64.encodebytes(hashed).decode('utf8').rstrip()
auth = f'LOG {access_key_id}:{signature}'
headers['Authorization'] = auth
PHP簽名範例程式碼
以下為請求籤名的程式碼範例,僅為參考:
<?php
// returns new headers array
function sign($method, $uri, $accessKeyId, $accessKeySecret, $params, $headers, $body)
{
$contentLength = 0;
$headers["x-log-apiversion"] = "0.6.0";
$headers["x-log-signaturemethod"] = "hmac-sha1";
if (!is_null($body) && strlen($body) > 0) {
$contentLength = strlen($body);
$contentMd5 = strtoupper(md5($body));
$headers["Content-MD5"] = $contentMd5;
}
// date
setLocale(LC_TIME, 'en_US');
$date = gmdate('D, d M Y H:i:s \G\M\T', time());
$headers["Date"] = $date;
$headers["Content-Length"] = (string)$contentLength;
$contentType = isset($headers['Content-Type']) ? $headers['Content-Type'] : '';
$message = $method . "\n" . $contentMd5 . "\n" . $contentType . "\n" . $date . "\n";
// header
$filterHeaders = [];
foreach ($headers as $key => $val) {
if (str_starts_with($key, 'x-log-') || str_starts_with($key, 'x-acs-')) {
$filterHeaders[$key] = $val;
}
}
ksort($filterHeaders);
foreach ($filterHeaders as $key => $val) {
$message .= $key . ':' . $val . "\n";
}
// uri and params
$message .= $uri;
if (sizeof($params) > 0) {
$message .= '?';
}
ksort($params);
$sep = '';
foreach ($params as $key => $val) {
$message .= $sep . $key . '=' . $val;
$sep = '&';
}
// signature & authorization
$signature = base64_encode(hash_hmac('sha1', $message, $accessKeySecret, TRUE));
$auth = 'LOG ' . $accessKeyId . ':' . $signature;
$headers['Authorization'] = $auth;
return $headers;
};
// example call
$headers = sign(
'POST',
'/logstores/test-logstore',
'testAccessId',
'testAccessKey',
array(
"test" => "test",
"hello" => "world"
),
array(
"x-log-signaturemethod" => "hmac-sha1",
"x-log-bodyrawsize" => "0",
"x-log-apiversion" => "0.6.0"
),
'hello, world'
);
echo ($headers['Authorization']);
foreach ($headers as $key => $val) {
echo ($key . '=' . $val . "\n");
}
?>
Go簽名範例程式碼
以下為請求籤名的程式碼範例,僅為參考:
package sls
import (
"crypto/hmac"
"crypto/md5"
"crypto/sha1"
"encoding/base64"
"fmt"
"sort"
"strconv"
"strings"
"time"
)
/*
* @param uri The uri of http request, exclude host and query param, eg: /logstores/test-logstore
* @param headers This function modifies headers, headers must not be a nil map
* @param method Http method in uppercase , eg: GET, POST, PUT, DELETE
*/
func Sign(method, uri, accessKeyID, accessKeySecret string, headers, queryParams map[string]string, body []byte) error {
var message, signature string
var contentMD5, contentType, date string
headers["x-log-apiversion"] = "0.6.0";
headers["x-log-signaturemethod"] = "hmac-sha1";
if len(body) > 0 {
contentMD5 = fmt.Sprintf("%X", md5.Sum(body))
headers["Content-MD5"] = contentMD5
}
date = time.Now().In(time.FixedZone("GMT", 0)).Format(time.RFC1123)
headers["Date"] = date
headers["Content-Length"] = strconv.Itoa(len(body))
if val, ok := headers["Content-Type"]; ok {
contentType = val
}
message += method + "\n" + contentMD5 + "\n" + contentType + "\n" + date + "\n"
// header
slsHeaders := make(map[string]string)
for k, v := range headers {
if strings.HasPrefix(k, "x-log-") || strings.HasPrefix(k, "x-acs-") {
slsHeaders[k] = v
}
}
forEachInOrder(slsHeaders, func(k, v string) {
message += k + ":" + v + "\n"
})
message += uri
if len(queryParams) > 0 {
message += "?"
}
sep := ""
forEachInOrder(queryParams, func(k, v string) {
message += sep + k + "=" + v
sep = "&"
})
// Signature = base64(hmac-sha1(UTF8-Encoding-Of(SignString),AccessKeySecret))
mac := hmac.New(sha1.New, []byte(accessKeySecret))
_, err := mac.Write([]byte(message))
if err != nil {
return err
}
signature = base64.StdEncoding.EncodeToString(mac.Sum(nil))
auth := fmt.Sprintf("LOG %v:%v", accessKeyID, signature)
headers["Authorization"] = auth
return nil
}
func forEachInOrder(m map[string]string, f func(k, v string)) {
var ss sort.StringSlice
for k := range m {
ss = append(ss, k)
}
ss.Sort()
for _, k := range ss {
f(k, m[k])
}
}
C#簽名範例程式碼
以下為請求籤名的程式碼範例,僅為參考:
using System.Security.Cryptography;
using System.Text;
using StringMap = System.Collections.Generic.Dictionary<string, string>;
void sign(string method, string uri,
string accessKeyId, string accessKeySecret,
StringMap queryParams,
StringMap headers,
byte[] body
)
{
int contentLength = 0;
string contentMd5 = "", message = "";
headers["x-log-apiversion"] = "0.6.0";
headers["x-log-signaturemethod"] = "hmac-sha1";
if (body != null && body.Length > 0)
{
contentLength = body.Length;
contentMd5 = BitConverter.ToString(MD5.Create().ComputeHash(body)).Replace("-", "");
Console.WriteLine(contentMd5);
headers["Content-MD5"] = contentMd5;
}
string date = DateTime.Now.ToUniversalTime().ToString("R");
headers["Date"] = date;
headers["Content-Length"] = contentLength.ToString();
message += method + "\n"
+ contentMd5 + "\n"
+ headers.GetValueOrDefault("Content-Type", "") + "\n"
+ date + "\n";
var sortedHeader = from entry in headers orderby entry.Key ascending select entry;
// header
foreach (var entry in sortedHeader)
{
if (entry.Key.StartsWith("x-log-") || entry.Key.StartsWith("x-acs-"))
{
message += entry.Key + ":" + entry.Value + "\n";
}
}
// url & params
message += uri;
if (queryParams.Count() > 0)
{
message += "?";
}
var sortedParam = from entry in queryParams orderby entry.Key ascending select entry;
string sep = "";
foreach (var entry in sortedParam)
{
message += sep + entry.Key + "=" + entry.Value;
sep = "&";
}
var hmac = new HMACSHA1(Encoding.ASCII.GetBytes(accessKeySecret));
var signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(message)));
var auth = "LOG " + accessKeyId + ":" + signature;
headers["Authorization"] = auth;
}
C++簽名範例程式碼
以下為請求籤名的程式碼範例,其中涉及的輔助函數,需要自行實現。樣本中的adapter.h標頭檔來自於Log ServiceC++ SDK,建議您參考Log ServiceC++ SDK進行簽名,具體操作,請參見C++ SDK快速入門。
CodecTool::CalcMD5(string) : 計算MD5值並轉為十六進位大寫字串。
CodecTool::StartWith(string, string) : 判斷字串是否含有另一字串作為首碼。
CodecTool::Base64Encode(string):Base64編碼字串。
CodecTool::CalcHMACSHA1(string, string): 計算hmac-sha1雜湊值。
CodecTool::GetDateString(): 擷取目前時間的格式化字串,格式為%a, %d %b %Y %H:%M:%S GMT
,例如Mon,3 Jan 2010 08:33:47 GMT。
#include <map>
#include <string>
#include <unordered_map>
#include <unordered_set>
#include <vector>
#include "adapter.h"
using namespace std;
using aliyun_log_sdk_v6::CodecTool;
void Sign(const string& httpMethod, const string& uri,
map<string, string>& httpHeaders,
const map<string, string>& urlParams, const string& body,
const string& accessKeyId, const string& accessKeySecret)
{
string message;
string contentMd5, signature, contentType;
httpHeaders["x-log-apiversion"] = "0.6.0";
httpHeaders["x-log-signaturemethod"] = "hmac-sha1";
// 1. Content-Md5
if (!body.empty())
{
contentMd5 = CodecTool::CalcMD5(body);
httpHeaders["Content-Md5"] = contentMd5;
}
// 2. Date
string dateTime = CodecTool::GetDateString();
httpHeaders["Date"] = dateTime;
// 3. Content-Length
string contentLength = std::to_string(body.size());
httpHeaders["Content-Length"] = contentLength;
// 4. Content-Type
if (httpHeaders.find("Content-Type") != httpHeaders.end())
{
contentType = httpHeaders["Content-Type"];
}
message.append(httpMethod).append("\n");
message.append(contentMd5).append("\n");
message.append(contentType).append("\n");
message.append(dateTime).append("\n");
// 5. header
map<string, string> filteredHeaders;
for (auto it : httpHeaders)
{
string key = it.first, value = it.second;
if (CodecTool::StartWith(key, "x-log-") ||
CodecTool::StartWith(key, "x-acs-"))
{
filteredHeaders[key] = value;
}
}
for (auto it : filteredHeaders)
{
message.append(it.first).append(":").append(it.second);
message.append("\n");
}
// 6. uri and url params
message.append(uri);
if (urlParams.size() > 0) message.append("?");
for (auto it = urlParams.begin(); it != urlParams.end(); ++it)
{
if (it != urlParams.begin())
{
message.append("&");
}
message.append(it->first).append("=").append(it->second);
}
// 7.Signature
signature = CodecTool::Base64Enconde(
CodecTool::CalcHMACSHA1(message, accessKeySecret));
// 8. authorization
httpHeaders["authorization"] =
"LOG " + accessKeyId + ':' + signature;
}
TypeScript簽名範例程式碼
該樣本依賴第三方庫crypto-js
,安裝依賴命令如下:
npm install crypto-js --save
以下為請求籤名的程式碼範例,僅為參考:
import CryptoJS from 'crypto-js'
export function sign(
method: string,
uri: string,
access_key_id: string,
access_key_secret: string,
params: Map<string, string>,
headers: Map<string, string>,
body: string | undefined
) {
let content_length = 0
let content_md5 = '',
message = ''
headers.set("x-log-apiversion", "0.6.0")
headers.set("x-log-signaturemethod", "hmac-sha1")
if (body !== undefined && body.length > 0) {
content_length = body.length
content_md5 = CryptoJS.MD5(body).toString(CryptoJS.enc.Hex).toUpperCase()
headers.set('Content-MD5', content_md5)
}
const date = new Date().toUTCString()
headers.set('Date', date)
headers.set('Content-Length', content_length.toString())
message +=
method +
'\n' +
content_md5 +
'\n' +
(headers.get('Content-Type') ?? '') +
'\n' +
date +
'\n'
// headers
const sort_by_key = (a: [string, string], b: [string, string]) =>
a[0].localeCompare(b[0])
const filter_by_prefix = (e: [string, string]) =>
e[0].startsWith('x-log-') || e[0].startsWith('x-acs-')
const header_str = [...headers.entries()]
.filter(filter_by_prefix)
.sort(sort_by_key)
.map((e) => e[0] + ':' + e[1] + '\n')
.join('')
message += header_str
// uri & query params
message += uri
if (params.size > 0) {
message += '?'
}
message += [...params.entries()]
.sort(sort_by_key)
.map((e) => e[0] + '=' + e[1])
.join('&')
// signature & authorization
const signature = CryptoJS.HmacSHA1(message, access_key_secret).toString(
CryptoJS.enc.Base64
)
const auth = 'LOG ' + access_key_id + ':' + signature
headers.set('Authorization', auth)
}
// example call
sign(
'POST',
'/logstores/test-logstore',
'testAccessId',
'testAccessKey',
new Map<string, string>([
['test', 'test'],
['hello', 'world'],
]),
new Map<string, string>([
['x-log-signaturemethod', 'hmac-sha1'],
['x-log-bodyrawsize', '0'],
['x-log-apiversion', '0.6.0'],
['Content-Type', 'application/json'],
]),
'hello, world'
)
Rust簽名範例程式碼
該樣本依賴庫名稱及版本如下所示:
[dependencies]
chrono = "0.4.19"
md5 = "0.7.0"
base64 = "0.13.0"
hmac-sha1 = "0.1.3"
以下為請求籤名的程式碼範例,僅為參考:
extern crate base64;
extern crate hmacsha1;
extern crate md5;
use chrono::Utc;
use std::collections::*;
pub fn sign(
method: &str,
uri: &str,
access_key_id: &str,
access_key_secret: &str,
params: &HashMap<String, String>,
headers: &mut HashMap<String, String>,
body: Option<Vec<u8>>,
) -> String {
let mut content_length = 0;
let mut content_md5 = String::from("");
headers.insert("x-log-apiversion".to_owned(), "0.6.0".to_owned());
headers.insert("x-log-signaturemethod".to_owned(), "hmac-sha1".to_owned());
if let Some(content) = body {
if content.len() > 0 {
content_length = content.len();
content_md5 = format!("{:X}", md5::compute(content));
headers.insert("Content-MD5".to_owned(), content_md5.clone());
}
}
headers.insert("Content-Length".to_owned(), content_length.to_string());
// date
let date = Utc::now().format("%a, %d %b %Y %H:%M:%S GMT").to_string();
headers.insert("Date".to_owned(), date.clone());
let mut message = "".to_owned();
let content_type = headers
.get(&"Content-Type".to_owned())
.cloned()
.unwrap_or(String::from(""));
message += format!("{}\n{}\n{}\n{}\n", method, content_md5, content_type, date).as_str();
// header
let mut sorted_header: Vec<_> = headers.iter().collect();
sorted_header.sort_by_key(|x| x.0);
for (k, v) in sorted_header {
if k.starts_with("x-log-") || k.starts_with("x-acs-") {
message += format!("{}:{}\n", k, v).as_str();
}
}
// url & params
message += uri;
if params.len() > 0 {
message += "?";
}
let mut sorted_params: Vec<_> = params.iter().collect();
sorted_params.sort_by_key(|x| x.0);
let mut sep = "";
for (k, v) in sorted_params {
message += format!("{}{}={}", sep, k, v).as_str();
sep = "&";
}
let signature = base64::encode(hmacsha1::hmac_sha1(
access_key_secret.as_bytes(),
message.as_bytes(),
));
let auth = format!("LOG {}:{}", access_key_id, signature);
headers.insert("Authorization".to_owned(), auth.to_owned());
auth
}