Udostępnij za pośrednictwem


Podpisywanie żądania HTTP przy użyciu kodu uwierzytelniania komunikatów opartego na skrótach (HMAC)

W tym artykule opisano sposób podpisywania żądania HTTP przy użyciu sygnatury uwierzytelniania komunikatów opartej na skrótach (HMAC).

Uwaga

Zalecamy użycie zestawów SDK platformy Azure do podpisania żądania HTTP. Podejście opisane w tym artykule jest opcją rezerwową, jeśli zestawy AZURE SDK nie mogą być używane z jakiegokolwiek powodu.

Z tego samouczka dowiesz się, jak wykonywać następujące działania:

  • Utwórz komunikat żądania.
  • Utwórz skrót zawartości.
  • Obliczanie podpisu.
  • Utwórz ciąg nagłówka autoryzacji.
  • Dodaj nagłówki.

Wymagania wstępne

Podpisywanie żądania HTTP przy użyciu języka C#

Uwierzytelnianie klucza dostępu używa wspólnego klucza tajnego do generowania podpisu HMAC dla każdego żądania HTTP. Ten podpis jest generowany za pomocą algorytmu SHA256 i jest wysyłany w nagłówku Authorization przy użyciu schematu HMAC-SHA256 . Na przykład:

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

hmac-sha256-signature składa się z:

  • Czasownik HTTP (na przykład GET lub PUT)
  • Ścieżka żądania HTTP
  • x-ms-data
  • Gospodarz
  • x-ms-content-sha256 (x-ms-zawartość-sha256)

Konfiguruj nagłówek autoryzacji

Wykonaj poniższe kroki, aby utworzyć nagłówek autoryzacyjny.

Tworzenie nowej aplikacji w języku C#

W oknie konsoli, takim jak cmd, PowerShell lub Bash, użyj dotnet new polecenia , aby utworzyć nową aplikację konsolową o nazwie SignHmacTutorial. To polecenie tworzy prosty projekt języka C# "Hello World" z jednym plikiem źródłowym: Program.cs.

dotnet new console -o SignHmacTutorial

Zmień katalog na nowo utworzony folder aplikacji. Aby skompilować aplikację, użyj dotnet build polecenia .

cd SignHmacTutorial
dotnet build

Instalowanie pakietu

Zainstaluj pakiet Newtonsoft.Json używany do serializacji ciała.

dotnet add package Newtonsoft.Json

Zaktualizuj deklarację Main metody w celu obsługi kodu asynchronicznego. Użyj poniższego kodu, aby rozpocząć.

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

Tworzenie komunikatu żądania

W tym przykładzie podpiszesz żądanie utworzenia nowej tożsamości przy użyciu interfejsu API uwierzytelniania usług komunikacyjnych (wersja 2021-03-07).

Dodaj następujący kod do metody 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")
};

Zamień resourceEndpoint na rzeczywistą wartość punktu końcowego zasobu, której używasz.

Utwórz skrót treści

Kryptograficzny skrót zawartości jest częścią podpisu HMAC. Użyj następującego kodu, aby obliczyć skrót zawartości. Tę metodę można dodać do Program.cs, znajdującego się w metodzie Main.

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

Obliczanie podpisu

Użyj poniższego kodu, aby utworzyć metodę przetwarzania podpisu 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);
}

Zastąp resourceAccessKey kluczem dostępu rzeczywistego zasobu Usług Komunikacyjnych.

Utwórz ciąg nagłówka autoryzacji

Teraz skonstruujesz ciąg znaków, który dodasz do nagłówka autoryzacji.

  1. Przygotuj wartości nagłówków do podpisania.
    1. Określ bieżącą sygnaturę czasową przy użyciu strefy czasowej uniwersalnej koordynowanej (UTC).
    2. Uzyskaj autoryzację do obsługi żądań. Użyj nazwy hosta lub adresu IP systemu nazw domen (DNS) i numeru portu.
    3. Oblicz skrót zawartości.
  2. Przygotuj ciąg do podpisu.
  3. Oblicz podpis.
  4. Połącz ciąg, który jest używany w nagłówku autoryzacyjnym.

Dodaj następujący kod do metody 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}";

Dodawanie nagłówków do requestMessage

Użyj następującego kodu, aby dodać wymagane nagłówki do parametru 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);

Testowanie klienta

Wywołaj punkt końcowy przy użyciu polecenia HttpClienti sprawdź odpowiedź.

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

Wymagania wstępne

Podpisywanie żądania HTTP przy użyciu języka Python

Uwierzytelnianie klucza dostępu używa wspólnego klucza tajnego do generowania podpisu HMAC dla każdego żądania HTTP. Ten podpis jest generowany za pomocą algorytmu SHA256 i jest wysyłany w nagłówku Authorization przy użyciu schematu HMAC-SHA256 . Na przykład:

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

hmac-sha256-signature składa się z:

  • Czasownik HTTP (na przykład GET lub PUT)
  • Ścieżka żądania HTTP
  • x-ms-data
  • Gospodarz
  • x-ms-content-sha256 (x-ms-zawartość-sha256)

Konfiguruj nagłówek autoryzacji

Wykonaj poniższe kroki, aby utworzyć nagłówek autoryzacji.

Tworzenie nowego skryptu języka Python

Otwórz Visual Studio Code lub inne środowisko IDE albo edytor według własnego wyboru. Utwórz nowy plik o nazwie sign_hmac_tutorial.py. Zapisz ten plik w znanym folderze.

Dodaj niezbędne importy

Zaktualizuj skrypt sign_hmac_tutorial.py za pomocą następującego kodu, aby rozpocząć.

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

Przygotowywanie danych do żądania

W tym przykładzie podpiszesz żądanie utworzenia nowej tożsamości przy użyciu interfejsu API uwierzytelniania usług komunikacyjnych (wersja 2021-03-07).

Dodaj następujący kod do skryptu sign_hmac_tutorial.py .

  • Zamień resource_endpoint_name na nazwę rzeczywistego punktu końcowego zasobu. Tę wartość można znaleźć w sekcji Przegląd zasobu usług komunikacyjnych. Jest to wartość Endpoint po https://.
  • Zastąp resource_endpoint_secret tajną wartością punktu końcowego zasobu. Tę wartość można znaleźć w sekcji Klucze zasobu usług komunikacyjnych. Jest to wartość Klucz, która jest podstawowa lub pomocnicza.
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 the list of scopes as a body.
body = { "createTokenWithScopes": ["chat"] }

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

Utwórz skrót treści

Kryptograficzny skrót zawartości jest częścią podpisu HMAC. Użyj następującego kodu, aby obliczyć skrót zawartości. Tę metodę można dodać do skryptu 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

Obliczanie podpisu

Użyj poniższego kodu, aby utworzyć metodę przetwarzania podpisu 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

Pobierz bieżący znacznik czasu UTC zgodnie ze standardem RFC1123

Użyj poniższego kodu, aby uzyskać format daty, który ma być niezależny od ustawień regionalnych.

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)

Utwórz ciąg nagłówka autoryzacji

Teraz skonstruujesz ciąg znaków, który dodasz do nagłówka autoryzacji.

  1. Przygotuj wartości nagłówków do podpisania.
    1. Określ bieżącą sygnaturę czasową przy użyciu strefy czasowej uniwersalnej koordynowanej (UTC).
    2. Uzyskaj autoryzację do obsługi żądań. Użyj nazwy hosta lub adresu IP systemu nazw domen (DNS) i numeru portu.
    3. Oblicz skrót zawartości.
  2. Przygotuj ciąg do podpisu.
  3. Oblicz podpis.
  4. Połącz ciąg, który jest używany w nagłówku autoryzacyjnym.

Dodaj następujący kod do skryptu 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}"

Dodawanie nagłówków

Użyj następującego kodu, aby dodać wymagane nagłówki.

request_headers = {}

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

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

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

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

Testowanie klienta

Wywołaj punkt końcowy i sprawdź odpowiedź.

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

Czyszczenie zasobów

Aby wyczyścić i usunąć subskrypcję usług Komunikacyjnych, usuń zasób lub grupę zasobów. Usunięcie grupy zasobów powoduje również usunięcie wszelkich innych skojarzonych z nią zasobów. Dowiedz się więcej na temat czyszczenia zasobów usług Azure Communication Services i czyszczenia zasobów usługi Azure Functions.