Assinar um pedido HTTP

Neste tutorial, irá aprender a assinar um pedido HTTP com uma assinatura HMAC.

Nota

Recomendamos vivamente a utilização de SDKs do Azure. A abordagem descrita aqui é uma opção de contingência para casos em que os SDKs do Azure não podem ser utilizados por qualquer motivo.

Pré-requisitos

Antes de começar, certifique-se de que:

Assinar um pedido HTTP com C #

A autenticação da chave de acesso utiliza uma chave secreta partilhada para gerar uma assinatura HMAC para cada pedido HTTP. Esta assinatura é gerada com o algoritmo SHA256 e é enviada no Authorization cabeçalho com o HMAC-SHA256 esquema. Por exemplo:

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

Consiste hmac-sha256-signature em:

  • Verbo HTTP (por exemplo, GET ou PUT)
  • Caminho do pedido HTTP
  • x-ms-date
  • Anfitrião
  • x-ms-content-sha256

Configuração

Os passos seguintes descrevem como construir o cabeçalho de autorização.

Criar uma nova aplicação C#

Numa janela da consola, como cmd, PowerShell ou Bash, utilize o dotnet new comando para criar uma nova aplicação de consola com o nome SignHmacTutorial. Este comando cria um projeto C# "Hello World" simples com um único ficheiro de origem: Program.cs.

dotnet new console -o SignHmacTutorial

Altere o diretório para a pasta da aplicação recentemente criada. Utilize o dotnet build comando para compilar a sua aplicação.

cd SignHmacTutorial
dotnet build

Instalar o pacote

Instale o pacote Newtonsoft.Json utilizado para serialização corporal.

dotnet add package Newtonsoft.Json

Atualize a declaração do Main método para suportar o código assíncrono. Utilize o seguinte código para começar.

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.
        }
    }
}

Criar uma mensagem de pedido

Neste exemplo, vamos assinar um pedido para criar uma nova identidade com a API de Autenticação dos Serviços de Comunicação (versão 2021-03-07).

Adicione o seguinte código ao 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")
};

Substitua pelo resourceEndpoint valor real do ponto final de recurso.

Criar um hash de conteúdo

O hash de conteúdo faz parte da assinatura HMAC. Utilize o código seguinte para calcular o hash de conteúdo. Pode adicionar este método ao Progam.cs no Main método .

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

Calcular uma assinatura

Utilize o seguinte código para criar um método para calcular a sua assinatura 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);
}

Substitua resourceAccessKey por uma chave de acesso do recurso real dos Serviços de Comunicação.

Criar uma cadeia de cabeçalho de autorização

Vamos agora construir a cadeia que vamos adicionar ao nosso cabeçalho de autorização.

  1. Preparar valores para os cabeçalhos a assinar.
    1. Especifique o carimbo de data/hora atual com o fuso horário Hora Universal Coordenada (UTC).
    2. Obtenha a autoridade de pedido (nome do anfitrião DNS ou endereço IP e o número da porta).
    3. Calcule um hash de conteúdo.
  2. Preparar uma cadeia para assinar.
  3. Calcule a assinatura.
  4. Concatenar a cadeia, que será utilizada no cabeçalho de autorização.

Adicione o seguinte código ao 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}";

Adicionar cabeçalhos a requestMessage

Utilize o seguinte código para adicionar os cabeçalhos necessários ao seu 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);

Testar o cliente

Chame o ponto final com HttpCliente verifique a resposta.

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

Pré-requisitos

Antes de começar, certifique-se de que:

Assinar um pedido HTTP com Python

A autenticação da chave de acesso utiliza uma chave secreta partilhada para gerar uma assinatura HMAC para cada pedido HTTP. Esta assinatura é gerada com o algoritmo SHA256 e é enviada no Authorization cabeçalho com o HMAC-SHA256 esquema. Por exemplo:

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

Consiste hmac-sha256-signature em:

  • Verbo HTTP (por exemplo, GET ou PUT)
  • Caminho do pedido HTTP
  • x-ms-date
  • Anfitrião
  • x-ms-content-sha256

Configuração

Os passos seguintes descrevem como construir o cabeçalho de autorização.

Criar um novo script python

Abra o Visual Studio Code ou outro IDE ou editor à sua escolha e crie um novo ficheiro com o nome sign_hmac_tutorial.py. Guarde este ficheiro numa pasta conhecida.

Adicionar as importações necessárias

Atualize o sign_hmac_tutorial.py script com o seguinte código para começar.

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

Preparar dados para o pedido

Neste exemplo, vamos assinar um pedido para criar uma nova identidade com a API de Autenticação dos Serviços de Comunicação (versão 2021-03-07).

Adicione o seguinte código ao sign_hmac_tutorial.py script.

  • Substitua pelo resource_endpoint_name valor de nome de ponto final de recurso real. Este valor pode ser encontrado na secção Descrição geral do recurso Azure Communication Services. É o valor de "Ponto Final" após "https://".
  • Substitua pelo resource_endpoint_secret valor de segredo do ponto final de recurso real. Este valor pode ser encontrado na secção Chaves do recurso Azure Communication Services. É o valor de "Chave" – principal ou secundário.
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")

Criar um hash de conteúdo

O hash de conteúdo faz parte da assinatura HMAC. Utilize o código seguinte para calcular o hash de conteúdo. Pode adicionar este método ao sign_hmac_tutorial.py script.

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

Calcular uma assinatura

Utilize o seguinte código para criar um método para calcular a sua assinatura 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

Obter o carimbo de data/hora UTC atual de acordo com a norma RFC1123

Utilize o seguinte código para obter o formato de data pretendido independentemente das definições de região.

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)

Criar uma cadeia de cabeçalho de autorização

Vamos agora construir a cadeia que vamos adicionar ao nosso cabeçalho de autorização.

  1. Preparar valores para os cabeçalhos a assinar.
    1. Especifique o carimbo de data/hora atual com o fuso horário Hora Universal Coordenada (UTC).
    2. Obtenha a autoridade de pedido (nome do anfitrião DNS ou endereço IP e o número da porta).
    3. Calcule um hash de conteúdo.
  2. Preparar uma cadeia para assinar.
  3. Calcule a assinatura.
  4. Concatenar a cadeia, que será utilizada no cabeçalho de autorização.

Adicione o seguinte código ao sign_hmac_tutorial.py script.

# 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}"

Adicionar cabeçalhos

Utilize o seguinte código para adicionar os cabeçalhos necessários.

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"

Testar o cliente

Ligue para o ponto final e verifique a resposta.

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

Limpar os recursos

Para limpar e remover uma subscrição dos Serviços de Comunicação, elimine o recurso ou o grupo de recursos. Eliminar o grupo de recursos também elimina quaisquer outros recursos associados ao mesmo. Pode saber mais sobre a limpeza Azure Communication Services recursos e a limpeza de recursos Funções do Azure.

Passos seguintes

Também poderá querer: