Appeler des opérations de l’API REST avec l’autorisation de clé partagéeCall REST API operations with Shared Key authorization

Cet article explique comment appeler les API REST Stockage Azure, et comment former l'en-tête d'autorisation.This article shows you how to call the Azure Storage REST APIs, including how to form the Authorization header. Il est écrit du point de vue d’un développeur qui n’a aucune connaissance sur REST et sur la manière de passer un appel REST.It's written from the point of view of a developer who knows nothing about REST and no idea how to make a REST call. Après avoir appris à appeler une opération REST, vous pouvez tirer parti de vos connaissances pour utiliser n'importe quelle autre opération REST Stockage Azure.After you learn how to call a REST operation, you can leverage this knowledge to use any other Azure Storage REST operations.

PrérequisPrerequisites

L'exemple d'application dresse la liste des conteneurs d'objets blob d'un compte de stockage.The sample application lists the blob containers for a storage account. Pour tester le code de cet article, vous avez besoin des éléments suivants :To try out the code in this article, you need the following items:

  • Installez Visual Studio 2019 avec la charge de travail Développement Azure.Install Visual Studio 2019 with the Azure development workload.

  • Un abonnement Azure.An Azure subscription. Si vous n’avez pas d’abonnement Azure, créez un compte gratuit avant de commencer.If you don't have an Azure subscription, create a free account before you begin.

  • Un compte de stockage à usage général.A general-purpose storage account. Si vous ne possédez pas encore de compte de stockage, consultez Création d’un compte de stockage.If you don't yet have a storage account, see Create a storage account.

  • L’exemple dans cet article illustre comment répertorier les conteneurs dans un compte de stockage.The example in this article shows how to list the containers in a storage account. Pour voir la sortie, ajoutez des conteneurs au Stockage Blob dans le compte de stockage avant de commencer.To see output, add some containers to blob storage in the storage account before you start.

Téléchargement de l'exemple d'applicationDownload the sample application

L’exemple d’application est une application console écrite en C#.The sample application is a console application written in C#.

Utilisez git pour télécharger une copie de l’application dans votre environnement de développement.Use git to download a copy of the application to your development environment.

git clone https://github.com/Azure-Samples/storage-dotnet-rest-api-with-auth.git

Cette commande clone le dépôt dans votre dossier git local.This command clones the repository to your local git folder. Pour ouvrir la solution Visual Studio, recherchez le dossier storage-dotnet-rest-api-with-auth, ouvrez-le et double-cliquez sur StorageRestApiAuth.sln.To open the Visual Studio solution, look for the storage-dotnet-rest-api-with-auth folder, open it, and double-click on StorageRestApiAuth.sln.

À propos de RESTAbout REST

REST est l'acronyme de Representational State Transfer.REST stands for representational state transfer. Consultez Wikipedia pour obtenir une définition spécifique.For a specific definition, check out Wikipedia.

REST est une architecture qui vous permet d'interagir avec un service via un protocole Internet, tel que HTTP/HTTPS.REST is an architecture that enables you to interact with a service over an internet protocol, such as HTTP/HTTPS. REST est indépendant du logiciel exécuté sur le serveur ou sur le client.REST is independent of the software running on the server or the client. L'API REST peut être appelée à partir de n'importe quelle plateforme prenant en charge le protocole HTTP/HTTPS.The REST API can be called from any platform that supports HTTP/HTTPS. Vous pouvez écrire une application sur Mac, Windows, Linux, un téléphone ou une tablette Android, iPhone, iPod, ou un site web, et vous pouvez utiliser la même API REST pour toutes ces plateformes.You can write an application that runs on a Mac, Windows, Linux, an Android phone or tablet, iPhone, iPod, or web site, and use the same REST API for all of those platforms.

Un appel à l'API REST se compose d'une requête, formulée par le client, et d'une réponse, renvoyée par le service.A call to the REST API consists of a request, which is made by the client, and a response, which is returned by the service. Dans la requête, vous envoyez une URL contenant des informations sur l'opération à appeler, la ressource à utiliser, les paramètres de requête et les en-têtes et, selon l'opération qui a été appelée, une charge utile de données.In the request, you send a URL with information about which operation you want to call, the resource to act upon, any query parameters and headers, and depending on the operation that was called, a payload of data. La réponse du service comprend un code d'état, un ensemble d'en-têtes de réponse et, selon l'opération qui a été appelée, une charge utile de données.The response from the service includes a status code, a set of response headers, and depending on the operation that was called, a payload of data.

À propos de l’exemple d’applicationAbout the sample application

L’exemple d’application liste les conteneurs dans un compte de stockage.The sample application lists the containers in a storage account. Une fois que vous comprenez la corrélation entre les informations dans la documentation sur l’API REST et votre code réel, les autres appels REST sont simples à comprendre.Once you understand how the information in the REST API documentation correlates to your actual code, other REST calls are easier to figure out.

Si vous regardez l’API REST du service Blob, vous voyez toutes les opérations que vous pouvez effectuer sur le Stockage Blob.If you look at the Blob Service REST API, you see all of the operations you can perform on blob storage. Les bibliothèques clientes de stockage sont des wrappers autour des API REST : elles vous permettent d’accéder facilement au stockage sans utiliser les API REST directement.The storage client libraries are wrappers around the REST APIs – they make it easy for you to access storage without using the REST APIs directly. Mais, comme indiqué précédemment, vous voulez parfois utiliser l’API REST au lieu d’une bibliothèque cliente de stockage.But as noted above, sometimes you want to use the REST API instead of a storage client library.

Opération List Containers (Répertorier les conteneurs)List Containers operation

Consultez la référence de l’opération ListContainers.Review the reference for the ListContainers operation. Ces informations vous aideront à comprendre d’où certains champs proviennent dans la requête et la réponse.This information will help you understand where some of the fields come from in the request and response.

Méthode de requête : GET.Request Method: GET. Ce verbe est la méthode HTTP que vous spécifiez en tant que propriété de l’objet de requête.This verb is the HTTP method you specify as a property of the request object. Les autres valeurs pour ce verbe incluent HEAD, PUT et DELETE en fonction de l’API que vous appelez.Other values for this verb include HEAD, PUT, and DELETE, depending on the API you are calling.

URI de requête : https://myaccount.blob.core.windows.net/?comp=list.Request URI: https://myaccount.blob.core.windows.net/?comp=list.  La requête est créée à partir du point de terminaison du compte de stockage d'objets blob http://myaccount.blob.core.windows.net et de la chaîne de ressources /?comp=list.  The request URI is created from the blob storage account endpoint http://myaccount.blob.core.windows.net and the resource string /?comp=list.

Paramètres d’URI : Il s’agit de paramètres de requête supplémentaires que vous pouvez utiliser lors de l’appel de ListContainers.URI parameters: There are additional query parameters you can use when calling ListContainers. Certains de ces paramètres sont timeout pour l’appel (en secondes) et prefix, utilisé pour le filtrage.A couple of these parameters are timeout for the call (in seconds) and prefix, which is used for filtering.

Un autre paramètre utile est maxresults: s’il existe plus de conteneurs disponibles que cette valeur, le corps de la réponse contiendra un élément NextMarker indiquant le conteneur suivant à retourner pour la requête suivante.Another helpful parameter is maxresults: if more containers are available than this value, the response body will contain a NextMarker element that indicates the next container to return on the next request. Pour utiliser cette fonctionnalité, vous fournissez la valeur NextMarker sous la forme du paramètre marker dans l’URI lors de la requête suivante.To use this feature, you provide the NextMarker value as the marker parameter in the URI when you make the next request. L’utilisation de cette fonctionnalité est similaire à la pagination des résultats.When using this feature, it is analogous to paging through the results.

Pour utiliser d’autres paramètres, ajoutez-les à la chaîne de ressource avec la valeur, comme par exemple :To use additional parameters, append them to the resource string with the value, like this example:

/?comp=list&timeout=60&maxresults=100

En-têtes de requête : Cette section répertorie les en-têtes de requête obligatoires et facultatifs.Request Headers: This section lists the required and optional request headers. Trois des en-têtes sont obligatoires : un en-tête Authorization, x-ms-date (contient l’heure UTC de la requête) et x-ms-version (spécifie la version de l’API REST à utiliser).Three of the headers are required: an Authorization header, x-ms-date (contains the UTC time for the request), and x-ms-version (specifies the version of the REST API to use). Inclure x-ms-client-request-id dans les en-têtes est facultatif. Vous pouvez définir ce champ sur n’importe quelle valeur ; il est écrit dans les journaux d’activité d’analytique du stockage lorsque la journalisation est activée.Including x-ms-client-request-id in the headers is optional – you can set the value for this field to anything; it is written to the storage analytics logs when logging is enabled.

Corps de la requête : Il n’existe pas de corps de requête pour ListContainers.Request Body: There is no request body for ListContainers. Le paramètre Corps de la requête est utilisé pour toutes les opérations PUT lors de la mise à jour d’objets Blob, tout comme SetContainerAccessPolicy, qui vous permet d’envoyer une liste XML des stratégies d’accès stockées à appliquer.Request Body is used on all of the PUT operations when uploading blobs, as well as SetContainerAccessPolicy, which allows you to send in an XML list of stored access policies to apply. Les stratégies d’accès stockées sont traitées dans l’article Utilisation des signatures d’accès partagé (SAP).Stored access policies are discussed in the article Using Shared Access Signatures (SAS).

Code d’état de la réponse : Indique tous les codes d’état que vous devez connaître.Response Status Code: Tells of any status codes you need to know. Dans cet exemple, un code d’état HTTP de 200 est acceptable.In this example, an HTTP status code of 200 is ok. Pour obtenir la liste complète des codes d’état HTTP, consultez Définitions des codes d’état.For a complete list of HTTP status codes, check out Status Code Definitions. Pour consulter les codes d’erreur spécifiques aux API REST de Stockage, consultez Codes d’erreur API REST courantsTo see error codes specific to the Storage REST APIs, see Common REST API error codes

En-têtes de réponse : Ils incluent Type de contenu ; x-ms-request-id, à savoir l’ID de requête que vous avez transmis ; x-ms-version, qui indique la version du service BLOB utilisé, et Date, au format UTC, qui indique l’heure à laquelle la requête a été faite.Response Headers: These include Content Type; x-ms-request-id, which is the request ID you passed in; x-ms-version, which indicates the version of the Blob service used; and the Date, which is in UTC and tells what time the request was made.

Corps de réponse : Ce champ est une structure XML qui fournit les données demandées.Response Body: This field is an XML structure providing the data requested. Dans cet exemple, la réponse est une liste de conteneurs et leurs propriétés.In this example, the response is a list of containers and their properties.

Création de la requête RESTCreating the REST request

À des fins de sécurité lors de l'exécution en production, utilisez toujours HTTPS plutôt que HTTP.For security when running in production, always use HTTPS rather than HTTP. Pour cet exercice, nous vous recommandons d’utiliser HTTP pour pouvoir afficher la requête et les données de la réponse.For the purposes of this exercise, you should use HTTP so you can view the request and response data. Pour afficher la requête et les informations de la réponse dans les appels REST réels, vous pouvez télécharger Fiddler ou une application similaire.To view the request and response information in the actual REST calls, you can download Fiddler or a similar application. Dans la solution Visual Studio, le nom et la clé du compte de stockage sont codés en dur dans la classe.In the Visual Studio solution, the storage account name and key are hardcoded in the class. La méthode ListContainersAsyncREST transmet le nom du compte de stockage et la clé du compte de stockage aux méthodes utilisées pour créer les divers composants de la requête REST.The ListContainersAsyncREST method passes the storage account name and storage account key to the methods that are used to create the various components of the REST request. Dans une application réelle, le nom et la clé du compte de stockage résident dans un fichier de configuration, des variables d’environnement ou sont récupérés à partir d’Azure Key Vault.In a real world application, the storage account name and key would reside in a configuration file, environment variables, or be retrieved from an Azure Key Vault.

Dans notre exemple de projet, le code pour créer l’en-tête d’autorisation se trouve dans une autre classe.In our sample project, the code for creating the Authorization header is in a separate class. L’idée est que vous pourriez prendre l’ensemble de la classe, l’ajouter à votre propre solution et l’utiliser « tel quel ».The idea is that you could take the whole class and add it to your own solution and use it "as is." Le code d’en-tête Autorisation fonctionne pour la plupart des appels d’API REST au Stockage Azure.The Authorization header code works for most REST API calls to Azure Storage.

Pour générer la requête, qui est un objet HttpRequestMessage, accédez à ListContainersAsyncREST dans Program.cs.To build the request, which is an HttpRequestMessage object, go to ListContainersAsyncREST in Program.cs. Les étapes de génération de la requête sont les suivantes :The steps for building the request are:

  • Créez l’URI à utiliser pour appeler le service.Create the URI to be used for calling the service.
  • Créez l’objet HttpRequestMessage et définissez la charge utile.Create the HttpRequestMessage object and set the payload. La charge utile a la valeur null pour ListContainersAsyncREST car nous ne transmettons rien.The payload is null for ListContainersAsyncREST because we're not passing anything in.
  • Ajoutez les en-têtes de la requête pour x-ms-date et x-ms-version.Add the request headers for x-ms-date and x-ms-version.
  • Obtenez l’en-tête d’autorisation et ajoutez-le.Get the authorization header and add it.

Informations de base dont vous avez besoin :Some basic information you need:

  • Pour ListContainers, la méthode est GET.For ListContainers, the method is GET. Cette valeur est définie lorsque la requête est instanciée.This value is set when instantiating the request.
  • La ressource est la partie de requête de l’URI qui indique quelle API est appelée, donc la valeur est /?comp=list.The resource is the query portion of the URI that indicates which API is being called, so the value is /?comp=list. Comme indiqué précédemment, la ressource se trouve sur la page de documentation de référence qui affiche les informations sur l’API ListContainers.As noted earlier, the resource is on the reference documentation page that shows the information about the ListContainers API.
  • L’URI est construit en créant le point de terminaison du service Blob pour ce compte de stockage et en concaténant la ressource.The URI is constructed by creating the Blob service endpoint for that storage account and concatenating the resource. La valeur de l’URI de requête devient http://contosorest.blob.core.windows.net/?comp=list.The value for request URI ends up being http://contosorest.blob.core.windows.net/?comp=list.
  • Pour ListContainers, requestBody a la valeur null et il n’y a aucun en-tête supplémentaire.For ListContainers, requestBody is null and there are no extra headers.

D’autres API peuvent avoir d’autres paramètres à transmettre, comme ifMatch.Different APIs may have other parameters to pass in such as ifMatch. L’appel de PutBlob est un exemple d’utilisation de ifMatch.An example of where you might use ifMatch is when calling PutBlob. Dans ce cas, vous définissez ifMatch sur une eTag, et l’objet Blob n’est mis à jour que si l’eTag que vous fournissez correspond à l’eTag actuelle de l’objet Blob.In that case, you set ifMatch to an eTag, and it only updates the blob if the eTag you provide matches the current eTag on the blob. Si un autre utilisateur a mis à jour l’objet Blob depuis la récupération de l’eTag, sa modification ne sera pas écrasée.If someone else has updated the blob since retrieving the eTag, their change won't be overridden.

Premièrement, définissez uri et payload.First, set the uri and the payload.

// Construct the URI. It will look like this:
//   https://myaccount.blob.core.windows.net/resource
String uri = string.Format("http://{0}.blob.core.windows.net?comp=list", storageAccountName);

// Provide the appropriate payload, in this case null.
//   we're not passing anything in.
Byte[] requestPayload = null;

Ensuite, instanciez la requête, en définissant la méthode sur GET et en fournissant l’URI.Next, instantiate the request, setting the method to GET and providing the URI.

// Instantiate the request message with a null payload.
using (var httpRequestMessage = new HttpRequestMessage(HttpMethod.Get, uri)
{ Content = (requestPayload == null) ? null : new ByteArrayContent(requestPayload) })
{

Ajoutez les en-têtes de requête pour x-ms-date et x-ms-version.Add the request headers for x-ms-date and x-ms-version. C’est à cet emplacement dans le code que vous ajoutez les en-têtes de requête supplémentaires requis pour l’appel.This place in the code is also where you add any additional request headers required for the call. Cet exemple ne contient pas d’en-tête supplémentaire.In this example, there are no additional headers. L'opération Set Container ACL est un exemple d'API transmettant des en-têtes supplémentaires.An example of an API that passes in extra headers is the Set Container ACL operation. Cet appel d'API ajoute un en-tête appelé « x-ms-blob-public-access » et la valeur du niveau d'accès.This API call adds a header called "x-ms-blob-public-access" and the value for the access level.

// Add the request headers for x-ms-date and x-ms-version.
DateTime now = DateTime.UtcNow;
httpRequestMessage.Headers.Add("x-ms-date", now.ToString("R", CultureInfo.InvariantCulture));
httpRequestMessage.Headers.Add("x-ms-version", "2017-07-29");
// If you need any additional headers, add them here before creating
//   the authorization header.

Appelez la méthode qui crée l’en-tête d’autorisation et ajoutez-le aux en-têtes de la requête.Call the method that creates the authorization header and add it to the request headers. Vous découvrirez comment créer l’en-tête d’autorisation plus loin dans cet article.You'll see how to create the authorization header later in the article. Le nom de la méthode est GetAuthorizationHeader, que vous pouvez voir dans cet extrait de code :The method name is GetAuthorizationHeader, which you can see in this code snippet:

// Get the authorization header and add it.
httpRequestMessage.Headers.Authorization = AzureStorageAuthenticationHelper.GetAuthorizationHeader(
    storageAccountName, storageAccountKey, now, httpRequestMessage);

httpRequestMessage contient la requête REST complète avec les en-têtes d’autorisation.At this point, httpRequestMessage contains the REST request complete with the authorization headers.

Envoyer la demandeSend the request

Maintenant que vous avez construit la demande, vous pouvez appeler la méthode SendAsync pour l’envoyer au stockage Azure.Now that you have constructed the request, you can call the SendAsync method to send it to Azure Storage. Vérifiez que la valeur du code d’état de la réponse est 200, ce qui signifie que l’opération a réussi.Check that the value of the response status code is 200, meaning that the operation has succeeded. Analysez ensuite la réponse.Next, parse the response. Dans ce cas, vous obtenez une liste XML de conteneurs.In this case, you get an XML list of containers. Observons le code utilisé pour appeler la méthode GetRESTRequest pour créer la requête, exécuter la requête, puis examiner dans la réponse la liste de conteneurs.Let's look at the code for calling the GetRESTRequest method to create the request, execute the request, and then examine the response for the list of containers.

    // Send the request.
    using (HttpResponseMessage httpResponseMessage =
      await new HttpClient().SendAsync(httpRequestMessage, cancellationToken))
    {
        // If successful (status code = 200),
        //   parse the XML response for the container names.
        if (httpResponseMessage.StatusCode == HttpStatusCode.OK)
        {
            String xmlString = await httpResponseMessage.Content.ReadAsStringAsync();
            XElement x = XElement.Parse(xmlString);
            foreach (XElement container in x.Element("Containers").Elements("Container"))
            {
                Console.WriteLine("Container name = {0}", container.Element("Name").Value);
            }
        }
    }
}

Si vous exécutez un sniffer réseau comme Fiddler lors de l’appel à SendAsync, vous pouvez voir la requête et les informations de la réponse.If you run a network sniffer such as Fiddler when making the call to SendAsync, you can see the request and response information. Jetons un œil sur cette configuration.Let's take a look. Le nom du compte de stockage est contosorest.The name of the storage account is contosorest.

Requête :Request:

GET /?comp=list HTTP/1.1

En-têtes de requête :Request Headers:

x-ms-date: Thu, 16 Nov 2017 23:34:04 GMT
x-ms-version: 2014-02-14
Authorization: SharedKey contosorest:1dVlYJWWJAOSHTCPGiwdX1rOS8B4fenYP/VrU0LfzQk=
Host: contosorest.blob.core.windows.net
Connection: Keep-Alive

Code d’état et en-têtes de réponse retournés après l’exécution :Status code and response headers returned after execution:

HTTP/1.1 200 OK
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 3e889876-001e-0039-6a3a-5f4396000000
x-ms-version: 2017-07-29
Date: Fri, 17 Nov 2017 00:23:42 GMT
Content-Length: 1511

Corps de la réponse (XML) : Pour l'opération List Containers, ce paramètre affiche la liste des conteneurs et leurs propriétés.Response body (XML): For the List Containers operation, this shows the list of containers and their properties.

<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults
  ServiceEndpoint="http://contosorest.blob.core.windows.net/">
  <Containers>
    <Container>
      <Name>container-1</Name>
      <Properties>
        <Last-Modified>Thu, 16 Mar 2017 22:39:48 GMT</Last-Modified>
        <Etag>"0x8D46CBD5A7C301D"</Etag>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Container>
    <Container>
      <Name>container-2</Name>
      <Properties>
        <Last-Modified>Thu, 16 Mar 2017 22:40:50 GMT</Last-Modified>
        <Etag>"0x8D46CBD7F49E9BD"</Etag>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Container>
    <Container>
      <Name>container-3</Name>
      <Properties>
        <Last-Modified>Thu, 16 Mar 2017 22:41:10 GMT</Last-Modified>
        <Etag>"0x8D46CBD8B243D68"</Etag>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
      </Properties>
    </Container>
    <Container>
      <Name>container-4</Name>
      <Properties>
        <Last-Modified>Thu, 16 Mar 2017 22:41:25 GMT</Last-Modified>
        <Etag>"0x8D46CBD93FED46F"</Etag>
        <LeaseStatus>unlocked</LeaseStatus>
        <LeaseState>available</LeaseState>
        </Properties>
      </Container>
      <Container>
        <Name>container-5</Name>
        <Properties>
          <Last-Modified>Thu, 16 Mar 2017 22:41:39 GMT</Last-Modified>
          <Etag>"0x8D46CBD9C762815"</Etag>
          <LeaseStatus>unlocked</LeaseStatus>
          <LeaseState>available</LeaseState>
        </Properties>
      </Container>
  </Containers>
  <NextMarker />
</EnumerationResults>

Maintenant que vous comprenez comment créer la requête, appeler le service et analyser les résultats, intéressons-nous à la création de l’en-tête d’autorisation.Now that you understand how to create the request, call the service, and parse the results, let's see how to create the authorization header. La création de cet en-tête est compliquée, mais la bonne nouvelle est que dès que vous disposez d’un code qui fonctionne, il fonctionne pour toutes les API REST du service Stockage.Creating that header is complicated, but the good news is that once you have the code working, it works for all of the Storage Service REST APIs.

Création de l’en-tête d’autorisationCreating the authorization header

Conseil

Le Stockage Azure prend désormais en charge l’intégration d’Azure Active Directory (Azure AD) pour les objets blob et les files d’attente.Azure Storage now supports Azure Active Directory (Azure AD) integration for blobs and queues. Azure AD offre une expérience beaucoup plus simple pour autoriser une requête destinée au Stockage Azure.Azure AD offers a much simpler experience for authorizing a request to Azure Storage. Pour plus d’informations sur l’utilisation d’Azure AD pour autoriser les opérations REST, consultez Autoriser avec Azure Active Directory.For more information on using Azure AD to authorize REST operations, see Authorize with Azure Active Directory. Pour une vue d’ensemble de l’intégration d’Azure AD au Stockage Azure, consultez Authentifier l’accès au Stockage Azure à l’aide d’Azure Active Directory.For an overview of Azure AD integration with Azure Storage, see Authenticate access to Azure Storage using Azure Active Directory.

Un article explique de manière conceptuelle (sans code) comment autoriser les demandes à Stockage Azure.There is an article that explains conceptually (no code) how to Authorize requests to Azure Storage.

Examinons cet article de plus près pour montrer le code.Let's distill that article down to exactly is needed and show the code.

Tout d’abord, utilisez une autorisation de clé partagée.First, use Shared Key authorization. Le format de l’en-tête d’autorisation ressemble à ce qui suit :The authorization header format looks like this:

Authorization="SharedKey <storage account name>:<signature>"  

Le champ de la signature est un code d’authentification de message basé sur le hachage (HMAC) créé à partir de la requête et calculé à l’aide de l’algorithme SHA256, puis encodé à l’aide de l’encodage Base64.The signature field is a Hash-based Message Authentication Code (HMAC) created from the request and calculated using the SHA256 algorithm, then encoded using Base64 encoding. Vous avez compris ?Got that? (Attendez, vous n’avez pas encore entendu l’expression rendre canonique.)(Hang in there, you haven't even heard the word canonicalized yet.)

Cet extrait de code affiche le format de la chaîne de signature par clé partagée :This code snippet shows the format of the Shared Key signature string:

StringToSign = VERB + "\n" +  
               Content-Encoding + "\n" +  
               Content-Language + "\n" +  
               Content-Length + "\n" +  
               Content-MD5 + "\n" +  
               Content-Type + "\n" +  
               Date + "\n" +  
               If-Modified-Since + "\n" +  
               If-Match + "\n" +  
               If-None-Match + "\n" +  
               If-Unmodified-Since + "\n" +  
               Range + "\n" +  
               CanonicalizedHeaders +  
               CanonicalizedResource;  

La plupart de ces champs est rarement utilisée.Most of these fields are rarely used. Pour le stockage Blob, vous spécifiez VERB, md5, content length (longueur du contenu), Canonicalized Headers (en-têtes rendus canoniques) et Canonicalized Resource (ressource rendue canonique).For Blob storage, you specify VERB, md5, content length, Canonicalized Headers, and Canonicalized Resource. Vous pouvez laisser les autres champs vides (mais insérez \n pour montrer qu’ils sont vides).You can leave the others blank (but put in the \n so it knows they are blank).

Que sont les champs CanonicalizedHeaders et CanonicalizedResource ?What are CanonicalizedHeaders and CanonicalizedResource? Bonne question.Good question. En fait, que signifie l’expression « rendre canonique » ?In fact, what does canonicalized mean? Microsoft Word ne la reconnaît même pas.Microsoft Word doesn't even recognize it as a word. Voici ce que Wikipédia indique sur le mot « canonique » : En informatique, la mise en forme canonique est le procédé par lequel on convertit des données qui ont plusieurs représentations possibles vers un format standard.Here's what Wikipedia says about canonicalization: In computer science, canonicalization (sometimes standardization or normalization) is a process for converting data that has more than one possible representation into a "standard", "normal", or canonical form. En langage courant, cela signifie prendre la liste d’éléments (comme des en-têtes dans le cas des En-têtes rendus canoniques) et les normaliser dans un format requis.In normal-speak, this means to take the list of items (such as headers in the case of Canonicalized Headers) and standardize them into a required format. En résumé, Microsoft a choisi un format et vous devez vous y conformer.Basically, Microsoft decided on a format and you need to match it.

Commençons par ces deux champs rendus canoniques, car ils sont obligatoires pour créer l’en-tête d’autorisation.Let's start with those two canonicalized fields, because they are required to create the Authorization header.

En-têtes rendus canoniquesCanonicalized headers

Pour créer cette valeur, récupérez les en-têtes qui commencent par « x-ms- » et triez-les, puis mettez-les en forme de chaîne d’instances [key:value\n], concaténées en une seule chaîne.To create this value, retrieve the headers that start with "x-ms-" and sort them, then format them into a string of [key:value\n] instances, concatenated into one string. Pour cet exemple, les en-têtes rendus canoniques ressemblent à ce qui suit :For this example, the canonicalized headers look like this:

x-ms-date:Fri, 17 Nov 2017 00:44:48 GMT\nx-ms-version:2017-07-29\n

Voici le code utilisé pour créer cette sortie :Here's the code used to create that output:

private static string GetCanonicalizedHeaders(HttpRequestMessage httpRequestMessage)
{
    var headers = from kvp in httpRequestMessage.Headers
        where kvp.Key.StartsWith("x-ms-", StringComparison.OrdinalIgnoreCase)
        orderby kvp.Key
        select new { Key = kvp.Key.ToLowerInvariant(), kvp.Value };

    StringBuilder headersBuilder = new StringBuilder();

    // Create the string in the right format; this is what makes the headers "canonicalized" --
    //   it means put in a standard format. https://en.wikipedia.org/wiki/Canonicalization
    foreach (var kvp in headers)
    {
        headersBuilder.Append(kvp.Key);
        char separator = ':';

        // Get the value for each header, strip out \r\n if found, then append it with the key.
        foreach (string headerValue in kvp.Value)
        {
            string trimmedValue = headerValue.TrimStart().Replace("\r\n", string.Empty);
            headersBuilder.Append(separator).Append(trimmedValue);

            // Set this to a comma; this will only be used
            // if there are multiple values for one of the headers.
            separator = ',';
        }

        headersBuilder.Append("\n");
    }

    return headersBuilder.ToString();
}

Ressource rendue canoniqueCanonicalized resource

Cette partie de la chaîne de signature représente le compte de stockage ciblé par la requête.This part of the signature string represents the storage account targeted by the request. N’oubliez pas que l’URI de requête est <http://contosorest.blob.core.windows.net/?comp=list>, avec le nom de compte réel (contosorest dans ce cas).Remember that the Request URI is <http://contosorest.blob.core.windows.net/?comp=list>, with the actual account name (contosorest in this case). Dans cet exemple, voici ce qui est retourné :In this example, this is returned:

/contosorest/\ncomp:list

Si vous avez des paramètres de requête, cet exemple les inclut également.If you have query parameters, this example includes those parameters as well. Voici le code, qui traite aussi les paramètres de requête supplémentaires et les paramètres de requête avec plusieurs valeurs.Here's the code, which also handles additional query parameters and query parameters with multiple values. N’oubliez pas que vous générez ce code pour qu’il fonctionne avec toutes les API REST.Remember that you're building this code to work for all of the REST APIs. Vous souhaitez inclure toutes les possibilités, même si la méthode ListContainers n’a pas besoin de toutes.You want to include all possibilities, even if the ListContainers method doesn't need all of them.

private static string GetCanonicalizedResource(Uri address, string storageAccountName)
{
    // The absolute path will be "/" because for we're getting a list of containers.
    StringBuilder sb = new StringBuilder("/").Append(storageAccountName).Append(address.AbsolutePath);

    // Address.Query is the resource, such as "?comp=list".
    // This ends up with a NameValueCollection with 1 entry having key=comp, value=list.
    // It will have more entries if you have more query parameters.
    NameValueCollection values = HttpUtility.ParseQueryString(address.Query);

    foreach (var item in values.AllKeys.OrderBy(k => k))
    {
        sb.Append('\n').Append(item.ToLower()).Append(':').Append(values[item]);
    }

    return sb.ToString();
}

Maintenant que les chaînes rendues canoniques sont définies, jetons un œil à la création de l’en-tête d’autorisation même.Now that the canonicalized strings are set, let's look at how to create the authorization header itself. Vous commencez par créer une chaîne de la signature du message au format StringToSign précédemment illustré dans cet article.You start by creating a string of the message signature in the format of StringToSign previously displayed in this article. Ce concept est plus facile à expliquer à l’aide de commentaires dans le code, donc voici la méthode finale qui retourne l’en-tête d’autorisation :This concept is easier to explain using comments in the code, so here it is, the final method that returns the Authorization Header:

internal static AuthenticationHeaderValue GetAuthorizationHeader(
    string storageAccountName, string storageAccountKey, DateTime now,
    HttpRequestMessage httpRequestMessage, string ifMatch = "", string md5 = "")
{
    // This is the raw representation of the message signature.
    HttpMethod method = httpRequestMessage.Method;
    String MessageSignature = String.Format("{0}\n\n\n{1}\n{5}\n\n\n\n{2}\n\n\n\n{3}{4}",
                method.ToString(),
                (method == HttpMethod.Get || method == HttpMethod.Head) ? String.Empty
                  : httpRequestMessage.Content.Headers.ContentLength.ToString(),
                ifMatch,
                GetCanonicalizedHeaders(httpRequestMessage),
                GetCanonicalizedResource(httpRequestMessage.RequestUri, storageAccountName),
                md5);

    // Now turn it into a byte array.
    byte[] SignatureBytes = Encoding.UTF8.GetBytes(MessageSignature);

    // Create the HMACSHA256 version of the storage key.
    HMACSHA256 SHA256 = new HMACSHA256(Convert.FromBase64String(storageAccountKey));

    // Compute the hash of the SignatureBytes and convert it to a base64 string.
    string signature = Convert.ToBase64String(SHA256.ComputeHash(SignatureBytes));

    // This is the actual header that will be added to the list of request headers.
    AuthenticationHeaderValue authHV = new AuthenticationHeaderValue("SharedKey",
        storageAccountName + ":" + signature);
    return authHV;
}

Lorsque vous exécutez ce code, le paramètre MessageSignature qui en résulte ressemble à cet exemple :When you run this code, the resulting MessageSignature looks like this example:

GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Fri, 17 Nov 2017 01:07:37 GMT\nx-ms-version:2017-07-29\n/contosorest/\ncomp:list

Voici la valeur finale pour AuthorizationHeader :Here's the final value for AuthorizationHeader:

SharedKey contosorest:Ms5sfwkA8nqTRw7Uury4MPHqM6Rj2nfgbYNvUKOa67w=

AuthorizationHeader est le dernier en-tête placé dans les en-têtes de la requête avant de publier la réponse.The AuthorizationHeader is the last header placed in the request headers before posting the response.

Ceci conclut tout ce que vous devez savoir pour créer une classe grâce à laquelle vous pouvez créer une requête pour appeler les API REST des services Stockage.That covers everything you need to know to put together a class with which you can create a request to call the Storage Services REST APIs.

Exemple : Liste des objets blobExample: List blobs

Voyons comment modifier le code afin d'appeler l'opération List Blobs pour le conteneur container-1.Let's look at how to change the code to call the List Blobs operation for container container-1. Ce code est presque identique au code utilisé pour lister les conteneurs, les seules différences étant l’URI et la façon d’analyser la réponse.This code is almost identical to the code for listing containers, the only differences being the URI and how you parse the response.

Si vous consultez la documentation de référence pour ListBlobs, vous constaterez que la méthode est GET et l’URI de la requête est :If you look at the reference documentation for ListBlobs, you find that the method is GET and the RequestURI is:

https://myaccount.blob.core.windows.net/container-1?restype=container&comp=list

Dans ListContainersAsyncREST, changez le code qui définit l’URI sur l’API pour ListBlobs.In ListContainersAsyncREST, change the code that sets the URI to the API for ListBlobs. Le nom du conteneur est container-1.The container name is container-1.

String uri =
    string.Format("http://{0}.blob.core.windows.net/container-1?restype=container&comp=list",
      storageAccountName);

Puis, là où vous traitez la réponse, changez le code pour rechercher des objets Blob au lieu de conteneurs.Then where you handle the response, change the code to look for blobs instead of containers.

foreach (XElement container in x.Element("Blobs").Elements("Blob"))
{
    Console.WriteLine("Blob name = {0}", container.Element("Name").Value);
}

Lorsque vous exécutez cet exemple, vous obtenez des résultats comme ceux ci-dessous :When you run this sample, you get results like the following:

En-têtes rendus canoniques :Canonicalized headers:

x-ms-date:Fri, 17 Nov 2017 05:16:48 GMT\nx-ms-version:2017-07-29\n

Ressource rendue canonique :Canonicalized resource:

/contosorest/container-1\ncomp:list\nrestype:container

Signature du message :Message signature:

GET\n\n\n\n\n\n\n\n\n\n\n\nx-ms-date:Fri, 17 Nov 2017 05:16:48 GMT
  \nx-ms-version:2017-07-29\n/contosorest/container-1\ncomp:list\nrestype:container

En-tête d'autorisation :Authorization header:

SharedKey contosorest:uzvWZN1WUIv2LYC6e3En10/7EIQJ5X9KtFQqrZkxi6s=

Les valeurs suivantes proviennent de Fiddler :The following values are from Fiddler:

Requête :Request:

GET http://contosorest.blob.core.windows.net/container-1?restype=container&comp=list HTTP/1.1

En-têtes de requête :Request Headers:

x-ms-date: Fri, 17 Nov 2017 05:16:48 GMT
x-ms-version: 2017-07-29
Authorization: SharedKey contosorest:uzvWZN1WUIv2LYC6e3En10/7EIQJ5X9KtFQqrZkxi6s=
Host: contosorest.blob.core.windows.net
Connection: Keep-Alive

Code d’état et en-têtes de réponse retournés après l’exécution :Status code and response headers returned after execution:

HTTP/1.1 200 OK
Content-Type: application/xml
Server: Windows-Azure-Blob/1.0 Microsoft-HTTPAPI/2.0
x-ms-request-id: 7e9316da-001e-0037-4063-5faf9d000000
x-ms-version: 2017-07-29
Date: Fri, 17 Nov 2017 05:20:21 GMT
Content-Length: 1135

Corps de la réponse (XML) : Cette réponse XML affiche la liste des objets Blob et leurs propriétés.Response body (XML): This XML response shows the list of blobs and their properties.

<?xml version="1.0" encoding="utf-8"?>
<EnumerationResults
    ServiceEndpoint="http://contosorest.blob.core.windows.net/" ContainerName="container-1">
    <Blobs>
        <Blob>
            <Name>DogInCatTree.png</Name>
            <Properties><Last-Modified>Fri, 17 Nov 2017 01:41:14 GMT</Last-Modified>
            <Etag>0x8D52D5C4A4C96B0</Etag>
            <Content-Length>419416</Content-Length>
            <Content-Type>image/png</Content-Type>
            <Content-Encoding />
            <Content-Language />
            <Content-MD5 />
            <Cache-Control />
            <Content-Disposition />
            <BlobType>BlockBlob</BlobType>
            <LeaseStatus>unlocked</LeaseStatus>
            <LeaseState>available</LeaseState>
            <ServerEncrypted>true</ServerEncrypted>
            </Properties>
        </Blob>
        <Blob>
            <Name>GuyEyeingOreos.png</Name>
            <Properties>
                <Last-Modified>Fri, 17 Nov 2017 01:41:14 GMT</Last-Modified>
                <Etag>0x8D52D5C4A25A6F6</Etag>
                <Content-Length>167464</Content-Length>
                <Content-Type>image/png</Content-Type>
                <Content-Encoding />
                <Content-Language />
                <Content-MD5 />
                <Cache-Control />
                <Content-Disposition />
                <BlobType>BlockBlob</BlobType>
                <LeaseStatus>unlocked</LeaseStatus>
                <LeaseState>available</LeaseState>
                <ServerEncrypted>true</ServerEncrypted>
            </Properties>
            </Blob>
        </Blobs>
    <NextMarker />
</EnumerationResults>

RésuméSummary

Dans cet article, vous avez appris à créer une requête vers l’API REST de stockage blob.In this article, you learned how to make a request to the blob storage REST API. Cette requête vous permet de récupérer une liste de conteneurs ou une liste d’objets blob dans un conteneur.With the request, you can retrieve a list of containers or a list of blobs in a container. Vous avez appris à créer la signature d’autorisation pour l’appel de l’API REST et à l’utiliser dans la requête REST.You learned how to create the authorization signature for the REST API call and how to use it in the REST request. Enfin, vous avez appris à examiner la réponse.Finally, you learned how to examine the response.

Étapes suivantesNext steps