全部產品
Search
文件中心

OpenSearch:v3 API 簽名機制

更新時間:Jul 13, 2024

OpenSearch服務會對每個訪問的請求進行身分識別驗證,通過使用Access Key ID和Access Key Secret進行對稱式加密的方法來驗證請求的寄件者身份。

Access Key ID和Access Key Secret由阿里雲官方頒發給訪問者(可以通過阿里雲官方網站申請和管理),其中Access Key ID用於標識訪問者的身份。

Access Key Secret是用於加密簽名字串和伺服器端驗證簽名字串的密鑰,必須嚴格保密,只有阿里雲和使用者知道。

支援應用類型

  • 進階版

  • 標準版

通訊協定

只支援 HTTP 協議

請求對應方式

  • 搜尋資料必須使用:GET

  • 推送資料必須使用:POST

Authorization 欄位計算方法

需在 HTTP 要求 Header 頭資訊中,添加 Authorization(授權)來包含簽名(Signature)資訊,表明該請求已被授權。請求Header 中也需要包含文檔下面“簽名樣本”部分中“請求Header”中提到的這些相關的請求Header。

請求 Header 中包含的參數都必須要參與簽名(例如 Content-Md5,Content-Type,Date,HTTP專有 Header 等等,同時還需要注意下:"Authorization: OPENSEARCH "中OPENSEARCH後面有一個空格)。

"Authorization: OPENSEARCH " + AccessKeyId + ":" + Signature
Signature = base64(hmac-sha1(AccessKeySecret,
            VERB + "\n"
            + Content-Md5 + "\n"
            + Content-Type + "\n"
            + Date + "\n"
            + CanonicalizedOpenSearchHeaders
            + CanonicalizedResource))

按照RFC2104的定義,使用上面的用於簽名的字串計算簽名HMAC值

  • 簽名的方法用 RFC 2104 中定義的 HMAC-SHA1 方法

  • 簽名的字串必須為UTF-8格式

  • 含有中文字元的簽名字串必須先進行UTF-8編碼,再與AccessKeySecret計算最終簽名

  • 簽名參數先後順序,必須和上面保持一致

參數

描述

AccessKeyId

不可為空,請求Header 中的 Authorization 需要用到該 AccessKeyId 值,表示訪問指定應用的使用者

AccessKeySecret

不可為空,簽名所需的密鑰

VERB

不可為空,表示請求操作方法。HTTP 要求 Method,主要有 PUT、GET、POST、HEAD、DELETE 等,不同介面Method也不同

\n

分行符號

Content-MD5

請求body有內容時,不可為空。該參數值為,請求body 的MD5值。該要求標頭用於訊息合法性的檢查(訊息內容是否與發送時一致),例如4991ef0788236a8f280fed0db928e74e

,對於不發送 body 的請求,例如查詢請求,此值請留空。詳情參看 RFC2616 Content-MD5

Content-Type

application/json

Date

不可為空,表示此次操作時間,且必須為 秒級 的 ISO 格式,如2019-02-25T10:09:57Z,時間為UTC時間;如果此時間和 OpenSearch 伺服器的時間差正負 15 分鐘以上,伺服器將拒絕該服務,並返回 HTTP 403 錯誤

CanonicalizedOpenSearchHeaders

不可為空,用於區分每次請求,以 X-Opensearch- 為首碼的HTTP專有 Header組合,例如 X-Opensearch-Nonce,在簽名過程中這些HTTP專有 Header名必須全部小寫,例如 x-opensearch-nonce,若這些HTTP專有Header是作為請求Header參數,則需按照原格式名顯示若請求 Header 中不包含這些HTTP專有 Header,該參數不參與簽名計算,在簽名方法中直接去掉該參數。

CanonicalizedResource

不可為空,表示使用者此次請求路徑,例如 /v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27%26%26sort%3Did%26%26config%3Dformat%3Afulljson

查詢請求

請求籤名參數

必須

請求 Header 參數

必須

AccessKeySecret

Date

VERB

X-Opensearch-Nonce

Date

Authorization

x-opensearch-nonce

canonicalized_resource

  • Header 中的參數值必須要與對應簽名方法中的參數值一致

  • 建議將 Content-Md5,Content-Type,Date,CanonicalizedOpenSearchHeaders,Authorization 這些參數都添加到請求Header中,只包含必須參數可能會出現報錯,需避免

  • 請求 Header 中包含的參數都必須要參與簽名

推送請求

請求籤名參數

必須

請求 Header 參數

必須

AccessKeySecret

Content-MD5

VERB

Date

Content-MD5

Authorization

Date

canonicalized_resource

  • Header 中的參數值必須要與對應簽名方法中的參數值一致

  • 理論上 Content-Md5,Content-Type,Date,CanonicalizedOpenSearchHeaders,Authorization 這些參數都需要添加到請求Header中,只包含必須參數可能會出現報錯,需避免

  • 請求 Header 中包含的參數都必須要參與簽名

構建CanonicalizedOpenSearchHeaders的方法

所有以 X-Opensearch- 為首碼的 HTTP專有 Header 被稱為 CanonicalizedOpenSearchHeaders,其他非 HTTP專有 Header 將不被納入驗證

  1. 將所有以 X-Opensearch- 為首碼的HTTP專有 Header 對應的內容補齊,例如X-Opensearch-Nonce : 1551089397451704(該Nonce參數值,可由10位時間戳記+6位隨機值(100000~999999)組合而成,例如1551089397451704),再去除所有值為空白的HTTP專有 Header

  2. 將這些有對應內容值的HTTP專有 Header 按照名稱的字典序進行升序排序

  3. 再將這些排序後的專有 Header名,全部轉換成小寫字母,例如將 X-Opensearch-Nonce : 1551089397451704 轉換成 x-opensearch-nonce : 1551089397451704

  4. 刪除要求標頭和內容之間分隔字元兩端出現的任何空格。例如該 x-opensearch-nonce : 1551089397451704 參數,刪除兩端空格後為:x-opensearch-nonce:1551089397451704

  5. 最後將每個要求標頭及對應內容作為一個單位項,再將每一項之間用 \n 串連拼成最後的 CanonicalizedOpenSearchHeaders,注意最後一個也要有 \n

說明

  1. 若查詢請求Header中不包含此處HTTP專有 Header,即該參數中一個HTTP專有 Header都沒有,則無需 \n,只需在簽名方法中去掉該CanonicalizedOpenSearchHeaders簽名參數即可,該參數不參與簽名計算。

  2. 將HTTP專有 Header添加到Header中時,不能是轉換後的小寫形式,需按原格式顯示

構建CanonicalizedResource的方法

  • 簽名的字串必須為UTF-8格式,且含有中文字元的簽名字串必須先進行 UTF-8 編碼,再與 AccessKeySecret 計算最終簽名

  • 查詢 CanonicalizedResource = path + ? + query

  • 推送 CanonicalizedResource = path

構建 path 部分

對 path 進行urlencode後,再替換 %2F/,下面的app_schema_demo需替換為自己應用程式名稱,常見 path 如下所示

  • search查詢path /v3/openapi/apps/app_schema_demo/search

  • suggest查詢path /v3/openapi/suggestions/suggestion_name/actions/search

  • 最終查詢指定應用資訊查詢請求串,下面“appid”需替換為待查詢的應用ID,需包含Authorization授權簽名參數(無需指定查詢參數) /v3/openapi/apps/appid

  • 推送資料path(tab 是要推送到應用中的某個具體表名,也需替換為自己應用表名)/v3/openapi/apps/app_schema_demo/tab/actions/bulk

構建 query 部分

query 部分由查詢參數構成,參數為索引值對形式

  1. 為需要指定的查詢參數設定對應的參數值,並去掉value為空白的參數(value為空白的參數不計算簽名)

  2. 再對每一個參數按照先比較參數名後比較參數值的順序,按照字典升序

  3. 再對每一部分的參數名參數值進行 urlencode(指定RFC 3986模式),再將參數名和對應參數值之間通過=拼接

  4. 再將各個查詢參數之間用 & 分割拼接並儲存到 query 字串中

  5. 最後按照 path + ? + query 方式拼接至CanonicalizedResource字串中,即完成查詢操作CanonicalizedResource參數構建,樣本如下:/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27%26%26sort%3Did%26%26config%3Dformat%3Afulljson

    • 以上請求串中主要包含的參數及參數值描述如下:

      • fetch_fields=name

    • 以上請求串中主要包含的query參數中各子句及參數值描述如下(第一個是query參數,第二個是query子句及其它相關子句):

      • query=query=name:'文檔'&&sort=id&&config=format:fulljson

說明

在urlencode之前,query參數中各個查詢子句之間必須要用 && 進行拼接,若為推送操作,則只需將 path 部分拼接至 CanonicalizedResource 字串中即可

構建 Authorization 欄位

構建方法參考開頭部分描述,需添加到請求 Header 中。假如AccessKeyId 為LTAItQcybixt****,Signature為 1P7tfEh+CU5kFYRXzZ14kkJU****,則python3範例程式碼大致如下:

headers['Authorization'] = 'OPENSEARCH ' + 'LTAIt****xt****' + ':' + '1P7tf*******4kkJU****'

簽名樣本

假如參數值如下

  • Authorization值為OPENSEARCH LTAItQ****R9A0:1P7tfEh+CU******14kkJ****

  • AccessKeySecret值為 R0OGKs*******khMqHXBfKG

  • 請求方式為GET

  • Content-MD5值為空白,此處作為查詢請求

  • Content-Type值為application/json

  • Date值為2019-02-25T10:09:57Z

  • CanonicalizedOpenSearchHeaders值為x-opensearch-nonce:15510****1704

  • CanonicalizedResource值為/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27%26%26sort%3Did%26%26config%3Dformat%3Afulljson

請求Header

簽名字串計算公式

簽名字串

‘Content-MD5’: ‘’,‘Content-Type’: ‘application/json’,‘Authorization’: ‘OPENSEARCH LTA****tR9A0:1P7tfEh+CU****RXzZ14kkJUAMc=’,‘X-Opensearch-Nonce’: ‘1551089397451704’,‘Date’: ‘2019-02-25T10:09:57Z’

Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n”+ Content-Md5 + “\n”+ Content-Type + “\n”+ Date + “\n”+ CanonicalizedOpenSearchHeaders+ CanonicalizedResource))

1P7tfEh+CU5k******4kkJUAMc= ,GET\n\napplication/json\n2019-02-25T10:09:57Z\nx-opensearch-nonce:1551089397451704\n/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27%26%26sort%3Did%26%26config%3Dformat%3Afulljson

說明

請求Header中參數值需與簽名方法中對應參數值保持一致

可用以下方法計算簽名(Signature)

  • 以 hash_hmac 和 base64_encode 編碼產生加密值作為Signature

python3 範例程式碼:

import hmac
import base64
signature_string = '\n'.join(['GET',
                              '',
                              'application/json',
                              '2019-02-25T10:09:57Z',
                              'x-opensearch-nonce:1551089397451704',
                              '/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27%26%26sort%3Did%26%26config%3Dformat%3Afulljson'])
signature_hmac = hmac.new('R0OGKsMj******khMqHXBfKG'.encode('utf-8'), signature_string.encode('utf-8'), 'sha1')
signature = base64.b64encode(signature_hmac.digest())

假如AccessKeySecret值為 R0OGKsMj0*********HXBfKG 那麼通過上面的簽名方法構造出來的簽名值為 1P7tfEh+CU5*******kkJUAMc=

構建請求串

請求串 = host + CanonicalizedResource

需在 HTTP 要求 Header 頭資訊中增加 Authorization(授權)來包含簽名(Signature)資訊,表明該請求已被授權,同時Header中也需要包含上面提到的這些相關的請求Header。(host為應用訪問API地址)

  • 最終search查詢請求串 http://host/v3/openapi/apps/app_schema_demo/search?fetch_fields=name&query=query%3Dname%3A%27%E6%96%87%E6%A1%A3%27%26%26sort%3Did%26%26config%3Dformat%3Afulljson

  • 最終suggest查詢請求串 http://host/v3/openapi/apps/{appName}/suggest/{suggestName}/search?hits=10&query=%E6%A0%87%E9%A2%98

  • 最終查詢指定應用資訊查詢請求串,下面最後一部分為“appid”值,假設為120001234該值,替換後如下所示,該查詢請求也需包含Authorization授權簽名參數(無需指定查詢參數) http://host/v3/openapi/apps/120001234

  • 最終推送資料請求串,此處推送資料需放在body體中 http://host/v3/openapi/apps/app_schema_demo/tab/actions/bulk

說明

  • 目前已對外公開 v3版官方Java SDK、PHP SDK、Python SDK,C# SDK,且PHP SDK和Python SDK、C# SDK已包含v3API簽名過程實現源碼,直接調用這些方法即可使用,也可參考 PHP SDK和Python SDK、C# SDK簽名實現過程源碼來實現其它語言SDK。

  • 後續使用者參考該文檔以及源碼實現的 SDK 由使用者自己維護。

應用結構模板

{
  "name": "app_schema_demo",
  "type": "standard",
  "schema": {
    "indexes": {
      "search_fields": {
        "id": {
          "fields": [
            "id"
          ]
        },
        "name": {
          "fields": [
            "name"
          ],
          "analyzer": "chn_standard"
        },
        "phone": {
          "fields": [
            "phone"
          ],
          "analyzer": "fuzzy"
        },
        "int_arr": {
          "fields": [
            "int_arr"
          ]
        },
        "literal_arr": {
          "fields": [
            "literal_arr"
          ]
        },
        "cate_id": {
          "fields": [
            "cate_id"
          ]
        }
      },
      "filter_fields": [
        "id",
        "int_arr",
        "literal_arr",
        "float_arr",
        "cate_id"
      ]
    },
    "tables": {
      "tab": {
        "name": "tab",
        "fields": {
          "id": {
            "name": "id",
            "type": "INT",
            "primary_key": true
          },
          "name": {
            "name": "name",
            "type": "TEXT",
            "primary_key": false
          },
          "phone": {
            "name": "phone",
            "type": "SHORT_TEXT",
            "primary_key": false
          },
          "int_arr": {
            "name": "int_arr",
            "type": "INT_ARRAY",
            "primary_key": false
          },
          "literal_arr": {
            "name": "literal_arr",
            "type": "LITERAL_ARRAY",
            "primary_key": false
          },
          "float_arr": {
            "name": "float_arr",
            "type": "FLOAT_ARRAY",
            "primary_key": false
          },
          "cate_id": {
            "name": "cate_id",
            "type": "INT",
            "primary_key": false
          }
        },
        "primary_table": true
      }
    },
    "route_field": null
  },
  "data_sources": [],
  "first_ranks": {},
  "second_ranks": {},
  "summary": [],
  "fetch_fields": [
    "id",
    "name",
    "phone",
    "int_arr",
    "literal_arr",
    "float_arr",
    "cate_id"
  ],
  "quota": {
    "qps": 6,
    "doc_size": 0.3
  }
}