All Products
Search
Document Center

Simple Log Service:Signature permintaan

Last Updated:Sep 15, 2026

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.

  • x-log-apiversion:0.6.0

  • x-log-bodyrawsize:0

  • x-log-signaturemethod:hmac-sha1

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:

  1. Buat pesan signature.

  2. Enkripsi pesan tersebut dengan HMAC-SHA1 menggunakan rahasia AccessKey Anda.

  3. 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
    }