本文为您详细介绍什么是v3API签名机制以及如何进行使用。
OpenSearch服务会对每个访问的请求进行身份验证,通过使用AccessKey ID和AccessKey Secret进行对称加密的方法来验证请求的发送者身份。
AccessKey ID和AccessKey Secret由阿里云官方颁发给访问者(可以通过阿里云官方网站申请和管理),其中AccessKey ID用于标识访问者的身份。
AccessKey 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值。该请求头用于消息合法性的检查(消息内容是否与发送时一致),例如 ,对于不发送 body 的请求,例如查询请求,此值请留空。详情参看 RFC2616 Content-MD5 | 
| Content-Type | 
 | 
| Date | 不能为空,表示此次操作时间,且必须为 秒级 的 ISO 格式,如 | 
| CanonicalizedOpenSearchHeaders | 不能为空,用于区分每次请求,以  | 
| CanonicalizedResource | 不能为空,表示用户此次请求路径,例如  | 
查询请求
| 请求签名参数 | 必须 | 请求 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 将不被纳入验证
- 将所有以 - X-Opensearch-为前缀的HTTP专有 Header 对应的内容补齐,例如- X-Opensearch-Nonce : 155108**********(该Nonce参数值,可由10位时间戳+6位随机值(100000~999999)组合而成,例如- 155108**********),再去除所有值为空的HTTP专有 Header
- 将这些有对应内容值的HTTP专有 Header 按照名称的字典序进行升序排序 
- 再将这些排序后的专有 Header名,全部转换成小写字母,例如将 - X-Opensearch-Nonce : 155108**********转换成- x-opensearch-nonce : 155108**********
- 删除请求头和内容之间分隔符两端出现的任何空格。例如该 - x-opensearch-nonce : 155108**********参数,删除两端空格后为:- x-opensearch-nonce:155108**********
- 最后将每个请求头及对应内容作为一个单位项,再将每一项之间用 - \n连接拼成最后的 CanonicalizedOpenSearchHeaders,注意最后一个也要有- \n
- 若查询请求Header中不包含此处HTTP专有 Header,即该参数中一个HTTP专有 Header都没有,则无需 \n,只需在签名方法中去掉该CanonicalizedOpenSearchHeaders签名参数即可,该参数不参与签名计算。 
- 将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 部分由查询参数构成,参数为键值对形式
- 为需要指定的查询参数设置对应的参数值,并去掉value为空的参数(value为空的参数不计算签名) 
- 再对每一个参数按照先比较 - 参数名后比较- 参数值的顺序,按照字典升序
- 再对每一部分的 - 参数名和- 参数值进行 urlencode(指定RFC 3986模式),再将参数名和对应参数值之间通过- =拼接
- 再将各个查询参数之间用 - &分割拼接并存储到 query 字符串中
- 最后按照 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 为LTAI****************,Signature为 1P7tfE****,则python3示例代码大致如下:
headers['Authorization'] = 'OPENSEARCH ' + 'LTAI****************' + ':' + '1P7tfE****'签名示例
假如参数值如下
- Authorization值为 - OPENSEARCH LTAI****************:1P7tfE****
- AccessKeySecret值为 - yourAccessKeySecret
- 请求方式为 - 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 LTAI****************:1P7tfE****’,‘X-Opensearch-Nonce’: ‘ | Signature = base64(hmac-sha1(AccessKeySecret,VERB + “\n”+ Content-Md5 + “\n”+ Content-Type + “\n”+ Date + “\n”+ CanonicalizedOpenSearchHeaders+ CanonicalizedResource)) | yourAccessKeySecret,GET\n\napplication/json\n2019-02-25T10:09:57Z\nx-opensearch-nonce: | 
请求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('yourAccessKeySecret'.encode('utf-8'), signature_string.encode('utf-8'), 'sha1')
signature = base64.b64encode(signature_hmac.digest())假如AccessKeySecret值为 yourAccessKeySecret 那么通过上面的签名方法构造出来的签名值为1P7tfE****
构建请求串
请求串 = 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
  }
}