Envío de una solicitud HTTP

En este tutorial aprenderá a firmar una solicitud HTTP con una firma HMAC.

Nota:

Se recomienda encarecidamente usar los SDK de Azure. El enfoque que se describe aquí es una opción alternativa para los casos en los que no se puedan usar los SDK de Azure por algún motivo.

Requisitos previos

Antes de comenzar, compruebe lo siguiente:

Envío de una solicitud HTTP con C#

La autenticación de clave de acceso usa una clave secreta compartida para generar una firma HMAC para cada solicitud HTTP. Esta firma se genera con el algoritmo SHA256 y se envía en el encabezado Authorization mediante el esquema HMAC-SHA256. Por ejemplo:

Authorization: "HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=<hmac-sha256-signature>"

hmac-sha256-signature consta de:

  • Verbo HTTP (por ejemplo, GET o PUT)
  • Ruta de acceso de la solicitud HTTP
  • x-ms-date
  • administrador de flujos de trabajo
  • x-ms-content-sha256

Configurar

En los pasos siguientes se describe cómo construir el encabezado de autorización.

Creación de una aplicación de C#

En una ventana de la consola, como cmd, PowerShell o Bash, use el comando dotnet new para crear una aplicación de consola con el nombre SignHmacTutorial. Este comando crea un sencillo proyecto "Hola mundo" de C# con un solo archivo de origen: Program.cs.

dotnet new console -o SignHmacTutorial

Cambie el directorio a la carpeta de aplicaciones recién creada. Use el comando dotnet build para compilar la aplicación.

cd SignHmacTutorial
dotnet build

Instalar el paquete

Instale el paquete Newtonsoft.Json que se usa en la serialización del cuerpo.

dotnet add package Newtonsoft.Json

Actualice la declaración del método Main para admitir código asincrónico. Use el código siguiente para empezar.

using System;
using System.Globalization;
using System.Net.Http;
using System.Security.Cryptography;
using System.Text;
using System.Threading.Tasks;
using Newtonsoft.Json;
namespace SignHmacTutorial
{
    class Program
    {
        static async Task Main(string[] args)
        {
            Console.WriteLine("Azure Communication Services - Sign an HTTP request Tutorial");
            // Tutorial code goes here.
        }
    }
}

Creación de un mensaje de solicitud

En este ejemplo se firma una solicitud para crear una identidad mediante Authentication API de Azure Communication Services (versión 2021-03-07).

Agregue el siguiente código al método Main.

string resourceEndpoint = "resourceEndpoint";
// Create a uri you are going to call.
var requestUri = new Uri($"{resourceEndpoint}/identities?api-version=2021-03-07");
// Endpoint identities?api-version=2021-03-07 accepts list of scopes as a body
var body = new
    {
        createTokenWithScopes = new[] { "chat" }
    };

var serializedBody = JsonConvert.SerializeObject(body);

var requestMessage = new HttpRequestMessage(HttpMethod.Post, requestUri)
{
    Content = new StringContent(serializedBody, Encoding.UTF8, "application/json")
};

Reemplace resourceEndpoint por el valor real del punto de conexión del recurso.

Creación de un hash de contenido

El código hash de contenido es parte de la firma HMAC. Agregue el código siguiente para procesar el código hash de contenido. Puede agregar este método a Progam.cs en el método Main.

static string ComputeContentHash(string content)
{
    using var sha256 = SHA256.Create();
    byte[] hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(content));
    return Convert.ToBase64String(hashedBytes);
}

Procesamiento de una firma

Use el código siguiente para crear un método para procesar una firma HMAC.

static string ComputeSignature(string stringToSign)
{
    string secret = "resourceAccessKey";
    using var hmacsha256 = new HMACSHA256(Convert.FromBase64String(secret));
    var bytes = Encoding.UTF8.GetBytes(stringToSign);
    var hashedBytes = hmacsha256.ComputeHash(bytes);
    return Convert.ToBase64String(hashedBytes);
}

Reemplace resourceAccessKey por la clave de acceso del recurso real de Communication Services.

Creación de una cadena de encabezado de autorización

Ahora crearemos la cadena que agregaremos a nuestro encabezado de autorización.

  1. Prepare los valores de los encabezados que se van a firmar.
    1. Especifique la marca de tiempo actual mediante la zona horaria hora universal coordinada (UTC).
    2. Obtenga la entidad de solicitud (nombre de host DNS o dirección IP y el número de puerto).
    3. Procese un hash de contenido.
  2. Prepare una cadena para firmar.
  3. Procese la firma.
  4. Concatene la cadena, que se usará en el encabezado de autorización.

Agregue el siguiente código al método Main.

// Specify the 'x-ms-date' header as the current UTC timestamp according to the RFC1123 standard
var date = DateTimeOffset.UtcNow.ToString("r", CultureInfo.InvariantCulture);
// Get the host name corresponding with the 'host' header.
var host = requestUri.Authority;
// Compute a content hash for the 'x-ms-content-sha256' header.
var contentHash = ComputeContentHash(serializedBody);

// Prepare a string to sign.
var stringToSign = $"POST\n{requestUri.PathAndQuery}\n{date};{host};{contentHash}";
// Compute the signature.
var signature = ComputeSignature(stringToSign);
// Concatenate the string, which will be used in the authorization header.
var authorizationHeader = $"HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature={signature}";

Incorporación de encabezados a requestMessage

Use el código siguiente para agregar los encabezados necesarios a requestMessage.

// Add a date header.
requestMessage.Headers.Add("x-ms-date", date);

// Add a host header.
// In C#, the 'host' header is added automatically by the 'HttpClient'. However, this step may be required on other platforms such as Node.js.

// Add a content hash header.
requestMessage.Headers.Add("x-ms-content-sha256", contentHash);

// Add an authorization header.
requestMessage.Headers.Add("Authorization", authorizationHeader);

Probar el cliente

Llame al punto de conexión mediante HttpClient y compruebe la respuesta.

HttpClient httpClient = new HttpClient
{
    BaseAddress = requestUri
};
var response = await httpClient.SendAsync(requestMessage);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);

Requisitos previos

Antes de comenzar, compruebe lo siguiente:

Firma de una solicitud HTTP con Python

La autenticación de clave de acceso usa una clave secreta compartida para generar una firma HMAC para cada solicitud HTTP. Esta firma se genera con el algoritmo SHA256 y se envía en el encabezado Authorization mediante el esquema HMAC-SHA256. Por ejemplo:

Authorization: "HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=<hmac-sha256-signature>"

hmac-sha256-signature consta de:

  • Verbo HTTP (por ejemplo, GET o PUT)
  • Ruta de acceso de la solicitud HTTP
  • x-ms-date
  • administrador de flujos de trabajo
  • x-ms-content-sha256

Configurar

En los pasos siguientes se describe cómo construir el encabezado de autorización.

Creación de un nuevo script de Python

Abra Visual Studio Code u otro IDE o editor de su elección y cree un nuevo archivo denominado sign_hmac_tutorial.py. Guarde este archivo en una carpeta conocida.

Adición de las importaciones necesarias

Actualice el script sign_hmac_tutorial.py con el código siguiente para comenzar.

import base64
import hashlib
import hmac
import json
from datetime import datetime, timezone
from urllib import request

Preparación de los datos para la solicitud

En este ejemplo se firma una solicitud para crear una identidad mediante Authentication API de Azure Communication Services (versión 2021-03-07).

Agregue el siguiente código al script sign_hmac_tutorial.py.

  • Reemplace resource_endpoint_name por el valor real del nombre de punto de conexión del recurso. Este valor se puede encontrar en la sección Información general del recurso de Azure Communication Services. Es el valor de "Endpoint" después de "https://".
  • Reemplace resource_endpoint_secret por el valor real del secreto del punto de conexión del recurso. Este valor se puede encontrar en la sección Claves del recurso de Azure Communication Services. Es el valor de "Key", ya sea principal o secundaria.
host = "resource_endpoint_name"
resource_endpoint = f"https://{host}"
path_and_query = "/identities?api-version=2021-03-07"
secret = "resource_endpoint_secret"

# Create a uri you are going to call.
request_uri = f"{resource_endpoint}{path_and_query}"

# Endpoint identities?api-version=2021-03-07 accepts list of scopes as a body.
body = { "createTokenWithScopes": ["chat"] }

serialized_body = json.dumps(body)
content = serialized_body.encode("utf-8")

Creación de un hash de contenido

El código hash de contenido es parte de la firma HMAC. Agregue el código siguiente para procesar el código hash de contenido. Puede agregar este método al script sign_hmac_tutorial.py.

def compute_content_hash(content):
    sha_256 = hashlib.sha256()
    sha_256.update(content)
    hashed_bytes = sha_256.digest()
    base64_encoded_bytes = base64.b64encode(hashed_bytes)
    content_hash = base64_encoded_bytes.decode('utf-8')
    return content_hash

Procesamiento de una firma

Use el código siguiente para crear un método para procesar una firma HMAC.

def compute_signature(string_to_sign, secret):
    decoded_secret = base64.b64decode(secret)
    encoded_string_to_sign = string_to_sign.encode('utf-8')
    hashed_bytes = hmac.digest(decoded_secret, encoded_string_to_sign, digest=hashlib.sha256)
    encoded_signature = base64.b64encode(hashed_bytes)
    signature = encoded_signature.decode('utf-8')
    return signature

Obtención de la marca de tiempo UTC actual según el estándar RFC1123

Use el código siguiente para obtener el formato de fecha deseado independientemente de la configuración regional.

def format_date(dt):
    days = ['Mon', 'Tue', 'Wed', 'Thu', 'Fri', 'Sat', 'Sun']
    months = ['Jan', 'Feb', 'Mar', 'Apr', 'May', 'Jun', 'Jul', 'Aug', 'Sep', 'Oct', 'Nov', 'Dec']
    utc = dt.utctimetuple()

    return "{}, {:02} {} {:04} {:02}:{:02}:{:02} GMT".format(
    days[utc.tm_wday],
    utc.tm_mday,
    months[utc.tm_mon-1],
    utc.tm_year,
    utc.tm_hour, 
    utc.tm_min, 
    utc.tm_sec)

Creación de una cadena de encabezado de autorización

Ahora crearemos la cadena que agregaremos a nuestro encabezado de autorización.

  1. Prepare los valores de los encabezados que se van a firmar.
    1. Especifique la marca de tiempo actual mediante la zona horaria hora universal coordinada (UTC).
    2. Obtenga la entidad de solicitud (nombre de host DNS o dirección IP y el número de puerto).
    3. Procese un hash de contenido.
  2. Prepare una cadena para firmar.
  3. Procese la firma.
  4. Concatene la cadena, que se usará en el encabezado de autorización.

Agregue el siguiente código al script sign_hmac_tutorial.py.

# Specify the 'x-ms-date' header as the current UTC timestamp according to the RFC1123 standard
utc_now = datetime.now(timezone.utc)
date = format_date(utc_now)
# Compute a content hash for the 'x-ms-content-sha256' header.
content_hash = compute_content_hash(content)

# Prepare a string to sign.
string_to_sign = f"POST\n{path_and_query}\n{date};{host};{content_hash}"
# Compute the signature.
signature = compute_signature(string_to_sign, secret)
# Concatenate the string, which will be used in the authorization header.
authorization_header = f"HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature={signature}"

Incorporación de encabezados

Use el código siguiente para agregar los encabezados necesarios.

request_headers = {}

# Add a date header.
request_headers["x-ms-date"] = date

# Add content hash header.
request_headers["x-ms-content-sha256"] = content_hash

# Add authorization header.
request_headers["Authorization"] = authorization_header

# Add content type header.
request_headers["Content-Type"] = "application/json"

Probar el cliente

Llame al punto de conexión y compruebe la respuesta.

req = request.Request(request_uri, content, request_headers, method='POST')
with request.urlopen(req) as response:
  response_string = json.load(response)
print(response_string)

Limpieza de recursos

Si quiere limpiar y quitar una suscripción de Communication Services, elimine el recurso o el grupo de recursos. Al eliminar el grupo de recursos, también se elimina cualquier otro recurso que esté asociado a él. Puede encontrar más información sobre la limpieza de los recursos de Azure Communication Services y la limpieza de los recursos de Azure Functions.

Pasos siguientes

También puede que desee consultar: