Подписывание HTTP-запроса

В этом учебнике описывается, как подписать HTTP-запрос с помощью подписи HMAC.

Примечание

Мы настоятельно рекомендуем использовать пакеты SDK для Azure. Описанный здесь подход является резервным вариантом для случаев, когда пакеты SDK для Azure нельзя использовать по какой-либо причине.

Предварительные требования

Перед началом работы нужно сделать следующее:

Подписывание HTTP-запроса с помощью C#

Проверка подлинности на основе ключа доступа использует для создания подписей HMAC для всех HTTP-запросов общий секретный ключ. Эта сигнатура создается с использованием алгоритма SHA256 и отправляется в заголовок Authorization с помощью схемы HMAC-SHA256. Например:

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

В состав hmac-sha256-signature входит следующее:

  • HTTP-команда (например, GET или PUT)
  • Путь HTTP-запроса
  • x-ms-date
  • Узел
  • x-ms-content-sha256

Настройка

Ниже описано, как создать заголовок авторизации.

Создание нового приложения C#

В окне консоли (cmd, PowerShell или Bash) выполните команду dotnet new, чтобы создать консольное приложение с именем SignHmacTutorial. Эта команда создает простой проект Hello World на языке C# с одним файлом исходного кода: Program.cs.

dotnet new console -o SignHmacTutorial

Измените каталог на созданную папку приложения. Используйте командуdotnet build для компиляции приложения.

cd SignHmacTutorial
dotnet build

Установка пакета

Установите пакет Newtonsoft.Json, который используется для сериализации текстовой части.

dotnet add package Newtonsoft.Json

Обновите объявление метода Main, чтобы он поддерживал асинхронный код. Используйте следующий код.

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

Создание сообщения запроса

В этом примере мы подпишем запрос на создание нового удостоверения с помощью API проверки подлинности Служб коммуникации Azure (версии 2021-03-07).

Добавьте в метод 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")
};

Замените resourceEndpoint фактическим значением конечной точки ресурса.

Создание хэша содержимого

Хэш содержимого является частью сигнатуры HMAC. Используйте следующий код, чтобы вычислить хэш содержимого. Этот метод можно добавить в Progam.cs, используя метод Main.

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

Вычисление сигнатуры

Используйте следующий код, чтобы создать метод для вычисления сигнатуры 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);
}

Замените resourceAccessKey ключом доступа к реальному ресурсу Служб коммуникации.

Создание строки заголовка авторизации

Далее мы создадим строку, которая будет добавлена в заголовок авторизации.

  1. Подготовьте значения для подписываемых заголовков.
    1. Укажите текущую метку времени, используя часовой пояс в формате UTC (Coordinated Universal Time).
    2. Получите данные об источнике запроса (имя узла DNS или IP-адрес и номер порта).
    3. Вычислите хэш содержимого.
  2. Подготовьте строку к подписыванию.
  3. Вычислите сигнатуру.
  4. Объедините строку, которая будет использована в заголовке авторизации.

Добавьте в метод 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}";

Добавление заголовков в requestMessage

Используйте следующий код, чтобы добавить необходимые заголовки в 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);

Тестирование клиента

Вызовите конечную точку с помощью HttpClient и проверьте ответ.

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

Предварительные требования

Перед началом работы нужно сделать следующее:

Подписание HTTP-запроса с помощью Python

Проверка подлинности на основе ключа доступа использует для создания подписей HMAC для всех HTTP-запросов общий секретный ключ. Эта сигнатура создается с использованием алгоритма SHA256 и отправляется в заголовок Authorization с помощью схемы HMAC-SHA256. Например:

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

В состав hmac-sha256-signature входит следующее:

  • HTTP-команда (например, GET или PUT)
  • Путь HTTP-запроса
  • x-ms-date
  • Узел
  • x-ms-content-sha256

Настройка

Ниже описано, как создать заголовок авторизации.

Создание сценария Python

Откройте Visual Studio Code или другую интегрированную среду разработки или редактор по своему выбору и создайте файл с именем sign_hmac_tutorial.py. Сохраните этот файл в известной папке.

Добавление необходимых операций импорта

Чтобы начать, sign_hmac_tutorial.py обновите скрипт, используя следующий код.

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

Подготовка данных для запроса

В этом примере мы подпишем запрос на создание нового удостоверения с помощью API проверки подлинности Служб коммуникации (версия 2021-03-07).

Добавьте следующий код в sign_hmac_tutorial.py скрипт.

  • Замените resource_endpoint_name реальным значением конечной точки ресурса. Это значение можно найти в разделе Обзор ресурса Службы коммуникации Azure. Это значение "Конечная точка" после "https://".
  • Замените resource_endpoint_secret реальным значением секрета конечной точки ресурса. Это значение можно найти в разделе Ключи ресурса Службы коммуникации Azure. Это значение "Ключ" — первичный или вторичный.
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")

Создание хэша содержимого

Хэш содержимого является частью сигнатуры HMAC. Используйте следующий код, чтобы вычислить хэш содержимого. Этот метод можно добавить в 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

Вычисление сигнатуры

Используйте следующий код, чтобы создать метод для вычисления сигнатуры 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

Получение текущей метки времени UTC в соответствии со стандартом RFC1123

Используйте следующий код, чтобы получить нужный формат даты независимо от параметров языкового стандарта.

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)

Создание строки заголовка авторизации

Далее мы создадим строку, которая будет добавлена в заголовок авторизации.

  1. Подготовьте значения для подписываемых заголовков.
    1. Укажите текущую метку времени, используя часовой пояс в формате UTC (Coordinated Universal Time).
    2. Получите данные об источнике запроса (имя узла DNS или IP-адрес и номер порта).
    3. Вычислите хэш содержимого.
  2. Подготовьте строку к подписыванию.
  3. Вычислите сигнатуру.
  4. Объедините строку, которая будет использована в заголовке авторизации.

Добавьте следующий код в 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}"

Добавление заголовков

Используйте следующий код, чтобы добавить необходимые заголовки.

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"

Тестирование клиента

Вызовите конечную точку и проверьте ответ.

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

Очистка ресурсов

Чтобы очистить и удалить подписку на Службы коммуникации, удалите ресурс или группу ресурсов. При этом удаляются все ресурсы, связанные с ней. См. дополнительные сведения об очистке ресурсов Служб коммуникации Azure и очистке ресурсов Функций Azure.

Дальнейшие действия

Кроме того, вам может понадобиться следующее: