Semua permintaan API SLS memerlukan autentikasi berbasis signature menggunakan pasangan AccessKey Alibaba Cloud dan penandatanganan HMAC-SHA1.
Catatan penggunaan
SDK SLS menangani penandatanganan secara otomatis dan mendukung beberapa bahasa. Gunakan SDK alih-alih penandatanganan manual bila memungkinkan. Ikhtisar SDK Simple Log Service.
Proses verifikasi keamanan:
-
Mengidentifikasi pemohon.
Pemohon menghasilkan signature digital menggunakan pasangan AccessKey. SLS menggunakan pasangan ini untuk verifikasi identitas dan kontrol akses.
-
Mendeteksi adanya perubahan pada permintaan.
SLS menghitung ulang signature di sisi server dan membandingkannya dengan signature yang dikirim oleh klien. Ketidakcocokan menunjukkan adanya perubahan, sehingga permintaan ditolak.
Penandatanganan memerlukan pasangan AccessKey. Pasangan AccessKey. Gunakan pasangan yang sudah ada atau buat yang baru, dan pastikan statusnya enabled.
Bagian berikut menjelaskan struktur permintaan, perhitungan tanda tangan, dan contoh kode penandatanganan.
Struktur permintaan
Tabel berikut mencantumkan field header HTTP yang wajib. Nilainya bersifat case-sensitive.
|
Field
|
Description
|
Example
|
|
x-log-signaturemethod
|
Metode enkripsi.
|
hmac-sha1
|
|
x-log-apiversion
|
Versi API.
|
0.6.0
|
|
Date
|
Timestamp HTTP standar dalam format RFC 822/1123 (GMT). Format: %a, %d %b %Y %H:%M:%S GMT.
|
Mon, 3 Jan 2010 08:33:47 GMT
|
|
Content-MD5
|
Hash MD5 dari badan permintaan, dalam bentuk string heksadesimal huruf besar.
|
72A15D7DE7EE9E7BB86461FFEA9499
|
|
Authorization
|
Signature permintaan. Format: LOG accessKeyId:Signature. Untuk informasi lebih lanjut tentang string signature, lihat Proses perhitungan tanda tangan.
|
LOG testAccessKeyId:RLETq4u7sWb3cssZIhsun****
|
|
Content-Type
|
Jenis badan permintaan HTTP. Abaikan field ini jika permintaan tidak memiliki badan.
|
application/json
|
Contoh permintaan HTTP yang telah ditandatangani:
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"}
Proses perhitungan tanda tangan
Header Authorization menggunakan format LOG accessKeyId:Signature, di mana AccessKeyId adalah ID kunci Anda dan Signature adalah string signature yang dihitung. Bagian ini menjelaskan cara membuat nilai Signature.
Pesan Tanda Tangan
String signature dihasilkan dengan mengenkripsi dan meng-encode pesan signature. Gambar berikut menunjukkan proses pembuatannya.
|
Parameter
|
Description
|
Example
|
|
method
|
Metode permintaan HTTP dalam huruf besar. Nilai yang valid: GET, POST, PUT, dan DELETE.
|
GET
|
|
Content-MD5
|
Hash MD5 dari badan permintaan dalam bentuk string heksadesimal huruf besar. String kosong jika tidak ada badan.
|
49DFDD54B01CBCD2D2AB5E9E5EE6B9B9
|
|
Content-Type
|
Jenis badan permintaan HTTP. String kosong jika tidak ada badan.
|
application/json
|
|
Date
|
Waktu saat ini dalam format RFC 822/1123 (GMT). Format: %a, %d %b %Y %H:%M:%S GMT.
|
Mon, 3 Jan 2010 08:33:47 GMT
|
|
Header
|
Header yang diawali dengan x-log- atau x-acs-, diurutkan berdasarkan kunci secara ascending. Kunci dan nilai digabungkan dengan colon (:), dan pasangan dipisahkan dengan line feed.
|
|
|
Uri
|
Jalur permintaan, tidak termasuk nama domain dan parameter kueri.
|
/logstores/test-logstore
|
|
Parameter terkait kueri
|
Parameter kueri diurutkan berdasarkan kunci secara ascending, digabungkan dengan = dan dipisahkan dengan &.
|
offset=1&size=10
|
Contoh pesan signature. Setiap baris kecuali yang terakhir diakhiri dengan line feed.
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
String signature
Untuk menghitung string signature:
-
Buat pesan signature.
-
Enkripsi pesan tersebut dengan HMAC-SHA1 menggunakan rahasia AccessKey Anda.
-
Encode hasilnya dalam Base64 untuk menghasilkan string signature.
Contoh
Contoh berikut menggunakan pasangan AccessKey ini:
AccessKeyId = "bq2sjzesjmo86kq****"
AccessKeySecret = "4fdO2fTDDnZPU/L7CHNd****"
-
Contoh 1
Daftarkan semua Logstore dalam ali-test-project menggunakan permintaan GET. Permintaan HTTP yang akan ditandatangani:
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
Pesan tanda tangan yang dihasilkan:
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
Karena permintaan GET tidak memiliki badan, Content-MD5 dan Content-Type berupa string kosong. Signature yang dihasilkan:
jEYOTCJs2e88o+y5F4/S5I****
Permintaan HTTP yang telah ditandatangani:
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****
-
Contoh 2
Tulis log berikut ke test-logstore dalam ali-test-project:
topic=""
time=1447048976
source="10.10.10.1"
"TestKey": "TestContent"
Permintaan HTTP yang akan ditandatangani:
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
<Log diserialisasi menjadi aliran byte dalam format Protobuf.>
Log diserialisasi dalam format Protocol Buffer (Protobuf) sebagai badan permintaan. Untuk informasi lebih lanjut tentang format Protobuf, lihat Pengkodean data. Content-Type adalah application/x-protobuf dan Content-MD5 adalah hash MD5 dari badan permintaan. Pesan signature yang dihasilkan:
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
Signature yang dihasilkan:
XWLGYHGg2F2hcfxWxMLiNk****
Permintaan HTTP yang telah ditandatangani:
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****
<Log diserialisasi menjadi aliran byte dalam format Protobuf.>
Kode contoh
-
Kode contoh dalam Java
Contoh ini menggunakan library commons-codec. Tambahkan dependensi berikut ke pom.xml:
<dependency>
<groupId>commons-codec</groupId>
<artifactId>commons-codec</artifactId>
<version>1.15</version>
</dependency>
Contoh penandatanganan:
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);
}
}
-
Kode contoh dalam Python
Contoh penandatanganan:
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
-
Kode contoh dalam PHP
Contoh penandatanganan:
<?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");
}
?>
-
Kode contoh dalam Go
Contoh penandatanganan:
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])
}
}
-
Kode contoh dalam C#
Contoh penandatanganan:
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;
}
-
Kode contoh dalam C++
Contoh penandatanganan. Implementasikan fungsi pembantu sesuai kebutuhan Anda. File header adapter.h merupakan bagian dari Simple Log Service SDK untuk C++. Kami merekomendasikan penandatanganan menggunakan SDK. Untuk informasi lebih lanjut, lihat Memulai Simple Log Service SDK untuk C++.
-
CodecTool::CalcMD5(string): menghitung nilai hash MD5 dan mengonversinya menjadi string heksadesimal berisi huruf besar.
-
CodecTool::StartWith(string, string): memeriksa apakah sebuah string diawali dengan string lain.
-
CodecTool::Base64Encode(string): meng-encode string dalam Base64.
-
CodecTool::CalcHMACSHA1(string, string): menggunakan algoritma HMAC-SHA1 untuk menghitung nilai hash.
-
CodecTool::GetDateString(): mendapatkan string waktu saat ini yang telah diformat. Format: %a, %d %b %Y %H:%M:%S GMT. Contoh: 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;
}
-
Kode contoh dalam TypeScript
Contoh ini menggunakan crypto-js. Instal dependensinya:
npm install crypto-js --save
Contoh penandatanganan:
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'
)
-
Kode contoh dalam Rust
Dependensi yang diperlukan:
[dependencies]
chrono = "0.4.19"
md5 = "0.7.0"
base64 = "0.13.0"
hmac-sha1 = "0.1.3"
Contoh penandatanganan:
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
}