OpenSearch authentifie chaque requête API par chiffrement symétrique basé sur des paires AccessKey. Chaque paire comprend un AccessKey ID et un AccessKey secret : l'ID identifie l'appelant, tandis que le secret signe la requête. Gardez votre AccessKey secret strictement confidentiel.
OpenSearch propose des SDK pour Java, PHP, Python et C#. Les SDK PHP, Python et C# intègrent nativement la logique de signature. Si un SDK est disponible pour votre langage, utilisez-le et ignorez cette rubrique. Si vous devez implémenter manuellement la signature ou déboguer une erreur de signature, suivez les étapes ci-dessous.
OpenSearch ne maintient ni les SDK développés à partir de cette rubrique, ni le code source des SDK officiels. Il incombe aux utilisateurs d'assurer la maintenance de ces SDK.
Prérequis
Avant de commencer, assurez-vous de disposer des éléments suivants :
Un AccessKey ID et un AccessKey secret obtenus depuis la console Alibaba Cloud
Une application OpenSearch (Advanced ou Standard)
Fonctionnement
La signature d'une requête comporte six étapes :
Construisez la chaîne
CanonicalizedOpenSearchHeadersà partir de tous les en-têtes de requête préfixés parX-Opensearch-*.Construisez la chaîne
CanonicalizedResourceà partir du chemin de la requête et des paramètres de requête.Assemblez la chaîne à signer en combinant la méthode HTTP, les en-têtes et les composants normalisés.
Calculez la signature HMAC-SHA1 de la chaîne à signer en utilisant l'AccessKey secret.
Encodez le résultat HMAC en Base64 pour obtenir la valeur finale de la signature.
Définissez l'en-tête
Authorizationen y incluant l'AccessKey ID et la signature.
Protocoles et méthodes de requête pris en charge
L'API OpenSearch V3 utilise exclusivement le protocole HTTP.
Envoyez des requêtes
GETpour rechercher des données.Envoyez des requêtes
POSTpour envoyer des données.
Étape 1 : Construire CanonicalizedOpenSearchHeaders
La variable CanonicalizedOpenSearchHeaders contient tous les en-têtes de requête préfixés par X-Opensearch- (par exemple, X-Opensearch-Nonce). Si la requête ne comporte aucun en-tête X-Opensearch-*, omettez entièrement ce composant de la chaîne à signer.
Pour construire cette chaîne :
Attribuez des valeurs à tous les en-têtes
X-Opensearch-*. Omettez tout en-tête dont la valeur est vide.Triez les en-têtes restants par ordre alphabétique selon leur nom.
Convertissez chaque nom d'en-tête en minuscules (par exemple,
X-Opensearch-Noncedevientx-opensearch-nonce).Supprimez tous les espaces autour du délimiteur
:dans chaque paire en-tête/valeur (par exemple,x-opensearch-nonce : valuedevientx-opensearch-nonce:value).Joignez toutes les paires en-tête/valeur avec
\net ajoutez un\naprès la dernière paire.
Lors de l'ajout des en-têtesX-Opensearch-*à la requête HTTP réelle, utilisez le format original avec casse mixte (X-Opensearch-Nonce), et non la forme en minuscules utilisée pour la signature.
Format de X-Opensearch-Nonce : Un horodatage de 10 chiffres concaténé avec une valeur aléatoire de 6 chiffres comprise entre 100000 et 999999 (par exemple, 155108**********).
Étape 2 : Construire CanonicalizedResource
Le format dépend du type de requête :
Requêtes de recherche :
path + ? + queryRequêtes d'envoi :
pathuniquement
Construire le chemin
Encodez la chaîne brute du chemin, remplacez %2F par /, et remplacez app_schema_demo par le nom de votre application :
| Type de requête | Format du chemin |
|---|---|
| Recherche de données | /v3/openapi/apps/<app-name>/search |
| Recherche par suggestion | /v3/openapi/suggestions/<suggestion-name>/actions/search |
| Recherche par ID d'application | /v3/openapi/apps/<app-id> |
| Envoi de données | /v3/openapi/apps/<app-name>/<table-name>/actions/bulk |
Construire la chaîne de requête (requêtes de recherche uniquement)
Attribuez des valeurs à chaque paramètre de requête. Omettez les paramètres dont la valeur est vide.
Triez les paramètres par ordre alphabétique, d'abord par clé, puis par valeur.
Encodez chaque clé et valeur en URL conformément à la RFC 3986. Joignez chaque paire avec
=.Concaténez toutes les paires avec
&.Concaténez les clauses de requête au sein du paramètre
queryen utilisant&&avant l'encodage.
Exemple de CanonicalizedResource pour une requête de recherche :
/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
Étape 3 : Assembler la chaîne à signer
"Authorization: OPENSEARCH " + AccessKeyId + ":" + Signature
Signature = base64(hmac-sha1(AccessKeySecret,
VERB + "\n"
+ Content-MD5 + "\n"
+ Content-Type + "\n"
+ Date + "\n"
+ CanonicalizedOpenSearchHeaders
+ CanonicalizedResource))
Tous les paramètres doivent apparaître dans l'ordre indiqué ci-dessus. La chaîne à signer doit être encodée en UTF-8. Si la chaîne contient des caractères chinois, encodez-les en UTF-8 avant de calculer le HMAC.
Incluez un espace aprèsOPENSEARCHdans la valeur de l'en-têteAuthorization.
Paramètres
| Paramètre | Obligatoire | Description |
|---|---|---|
AccessKeyId |
Oui | Votre AccessKey ID. Inclus dans l'en-tête Authorization. |
AccessKeySecret |
Oui | Votre AccessKey secret. Utilisé pour calculer le HMAC. Ne doit jamais être inclus dans la requête. |
VERB |
Oui | Méthode HTTP : GET, POST, PUT, HEAD ou DELETE. |
Content-MD5 |
Conditionnel | Valeur MD5 du corps de la requête HTTP (exemple : 4991ef0788236a8f280fed0db928e74e). Obligatoire pour les requêtes d'envoi. Laissez vide pour les requêtes de recherche. Consultez la RFC 2616. |
Content-Type |
— | Type MIME du corps de la requête (exemple : application/json). |
Date |
Oui | Horodatage de la requête au format ISO 8601 : YYYY-MM-DDThh:mm:ssZ (UTC). Exemple : 2019-02-25T10:09:57Z. OpenSearch rejette les requêtes dont l'horodatage diffère de plus de 15 minutes de l'heure du serveur, en renvoyant une erreur HTTP 403. |
CanonicalizedOpenSearchHeaders |
Conditionnel | Tous les en-têtes X-Opensearch-*, en minuscules et triés. Omettez cette ligne de la chaîne à signer si la requête ne contient aucun en-tête X-Opensearch-*. |
CanonicalizedResource |
Oui | Le chemin de la requête et la chaîne de requête normalisés. |
Étape 4 : Calculer la signature HMAC-SHA1
Utilisez HMAC-SHA1 tel que défini dans la RFC 2104 pour signer la chaîne à signer, en utilisant l'AccessKey secret comme clé.
Étape 5 : Encoder le digest en Base64
Encodez en Base64 les octets bruts du digest HMAC-SHA1 pour produire la valeur finale de la signature.
Étape 6 : Définir l'en-tête Authorization
Authorization: OPENSEARCH <AccessKeyId>:<Signature>
Exemple en Python 3 :
headers['Authorization'] = 'OPENSEARCH ' + 'LTAI****************' + ':' + '1P7tfE****'
En-têtes requis par type de requête
Requêtes de recherche
| Paramètre de signature | Obligatoire | En-tête de requête | Obligatoire |
|---|---|---|---|
AccessKeySecret |
Oui | Date |
Oui |
VERB |
Oui | X-Opensearch-Nonce |
Oui |
Date |
Oui | Authorization |
Oui |
x-opensearch-nonce |
Oui | ||
canonicalized_resource |
Oui |
Requêtes d'envoi
| Paramètre de signature | Obligatoire | En-tête de requête | Obligatoire |
|---|---|---|---|
AccessKeySecret |
Oui | Content-MD5 |
Oui |
VERB |
Oui | Date |
Oui |
Content-MD5 |
Oui | Authorization |
Oui |
Date |
Oui | ||
canonicalized_resource |
Oui |
Les valeurs des en-têtes envoyées dans la requête HTTP doivent correspondre exactement aux valeurs utilisées lors du calcul de la signature. Incluez les en-têtes Content-MD5, Content-Type, Date, CanonicalizedOpenSearchHeaders et Authorization dans chaque requête pour éviter les erreurs.
Exemple complet
Cet exemple signe une requête de recherche avec les valeurs suivantes :
| Composant | Valeur |
|---|---|
| Méthode de requête | GET |
| AccessKey secret | yourAccessKeySecret |
| Content-MD5 | (vide — la requête de recherche n'a pas de corps) |
| Content-Type | application/json |
| Date | 2019-02-25T10:09:57Z |
| CanonicalizedOpenSearchHeaders | x-opensearch-nonce:1551089397451704 |
| 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 |
Chaîne à signer (utilisez cette valeur intermédiaire pour vérifier votre implémentation) :
GET\n
\n
application/json\n
2019-02-25T10:09:57Z\n
x-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
Calcul de la signature (Python 3) :
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())
Signature finale : 1P7tfE****
En-têtes de la requête :
Content-MD5:
Content-Type: application/json
Authorization: OPENSEARCH LTAI****************:1P7tfE****
X-Opensearch-Nonce: 1551089397451704
Date: 2019-02-25T10:09:57Z
Format de la chaîne de requête
Une URL de requête complète suit le format host + CanonicalizedResource. Dans une chaîne de requête, host spécifie l'endpoint de l'API OpenSearch.
| Type de requête | Exemple d'URL |
|---|---|
| Recherche de données | 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 |
| Recherche par suggestion | http://host/v3/openapi/apps/{appName}/suggest/{suggestName}/search?hits=10&query=%E6%A0%87%E9%A2%98 |
| Recherche par ID d'application | http://host/v3/openapi/apps/120001234 |
| Envoi de données | http://host/v3/openapi/apps/app_schema_demo/tab/actions/bulk |
Modèle de schéma d'application
{
"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
}
}
Dépannage
Erreur HTTP 403 sur chaque requête
La cause la plus fréquente est un horodatage en dehors de la fenêtre de tolérance de 15 minutes. Assurez-vous que l'en-tête Date utilise l'heure UTC actuelle au format ISO 8601 (YYYY-MM-DDThh:mm:ssZ) et que l'horloge de votre système est synchronisée.
Incompatibilité de signature
Vérifiez les points suivants dans l'ordre :
Vérifiez que la chaîne à signer correspond à la valeur intermédiaire de l'exemple ci-dessus — calculez la chaîne à signer pour votre requête et journalisez-la avant le hachage.
Confirmez que
Content-MD5est vide pour les requêtesGET.Confirmez que les noms d'en-tête
CanonicalizedOpenSearchHeaderssont en minuscules et triés par ordre alphabétique.Confirmez que les clauses du paramètre
querysont concaténées avec&&avant l'encodage URL.Confirmez que la chaîne de signature et l'AccessKey secret sont tous deux encodés en UTF-8 avant le calcul du HMAC.