Firmare una richiesta HTTP
In questa esercitazione si apprenderà come firmare una richiesta HTTP con una firma HMAC.
Nota
Si consiglia vivamente di usare Gli SDK di Azure. L'approccio descritto di seguito è un'opzione di fallback per i casi in cui gli SDK di Azure non possono essere usati per qualsiasi motivo.
Prerequisiti
Prima di iniziare, assicurarsi di:
- Creare un account Azure con una sottoscrizione attiva. Per informazioni dettagliate, vedere Creare un account gratuito.
- Installare Visual Studio.
- Creare una risorsa di Servizi di comunicazione di Azure. Per informazioni dettagliate, vedere Creare una risorsa Servizi di comunicazione di Azure. Per questa esercitazione è necessario registrare resourceEndpoint e resourceAccessKey .
Firmare una richiesta HTTP con C #
L'autenticazione con chiave di accesso usa una chiave privata condivisa per generare una firma HMAC per ogni richiesta HTTP. Questa firma viene generata con l'algoritmo SHA256 e viene inviata nell'intestazione Authorization
usando lo HMAC-SHA256
schema . Ad esempio:
Authorization: "HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=<hmac-sha256-signature>"
L'oggetto hmac-sha256-signature
è costituito da:
- Verbo HTTP (ad esempio,
GET
oPUT
) - Percorso della richiesta HTTP
- x-ms-date
- Host
- x-ms-content-sha256
Installazione
I passaggi seguenti descrivono come costruire l'intestazione di autorizzazione.
Creare una nuova applicazione C#
In una finestra della console, ad esempio cmd, PowerShell o Bash, usare il dotnet new
comando per creare una nuova app console con il nome SignHmacTutorial
. Questo comando crea un semplice progetto C# "Hello World" con un singolo file di origine: Program.cs.
dotnet new console -o SignHmacTutorial
Spostarsi nella cartella dell'app appena creata. Usare il comando per compilare l'applicazione dotnet build
.
cd SignHmacTutorial
dotnet build
Installare il pacchetto
Installare il pacchetto Newtonsoft.Json
usato per la serializzazione del corpo.
dotnet add package Newtonsoft.Json
Aggiornare la dichiarazione del Main
metodo per supportare il codice asincrono. Usare il codice seguente per iniziare.
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.
}
}
}
Creare un messaggio di richiesta
Per questo esempio si firmerà una richiesta per creare una nuova identità usando l'API di autenticazione di Servizi di comunicazione (versione 2021-03-07
).
Aggiungere il codice seguente al metodo 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")
};
Sostituire resourceEndpoint
con il valore dell'endpoint risorsa reale.
Creare un hash del contenuto
L'hash del contenuto fa parte della firma HMAC. Usare il codice seguente per calcolare l'hash del contenuto. È possibile aggiungere questo metodo a Progam.cs
nel Main
metodo .
static string ComputeContentHash(string content)
{
using var sha256 = SHA256.Create();
byte[] hashedBytes = sha256.ComputeHash(Encoding.UTF8.GetBytes(content));
return Convert.ToBase64String(hashedBytes);
}
Calcolare una firma
Usare il codice seguente per creare un metodo per calcolare la 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);
}
Sostituire resourceAccessKey
con una chiave di accesso della risorsa di Servizi di comunicazione reale.
Creare una stringa di intestazione di autorizzazione
Verrà ora creata la stringa che verrà aggiunta all'intestazione di autorizzazione.
- Preparare i valori per le intestazioni da firmare.
- Specificare il timestamp corrente usando il fuso orario UTC (Coordinated Universal Time).
- Ottenere l'autorità di richiesta (nome host DNS o indirizzo IP e numero di porta).
- Calcolare un hash del contenuto.
- Preparare una stringa per firmare.
- Calcolare la firma.
- Concatenare la stringa, che verrà usata nell'intestazione dell'autorizzazione.
Aggiungere il codice seguente al metodo 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}";
Aggiungere intestazioni a requestMessage
Usare il codice seguente per aggiungere le intestazioni necessarie 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);
Testare il client
Chiamare l'endpoint usando HttpClient
e controllare la risposta.
HttpClient httpClient = new HttpClient
{
BaseAddress = requestUri
};
var response = await httpClient.SendAsync(requestMessage);
var responseString = await response.Content.ReadAsStringAsync();
Console.WriteLine(responseString);
Prerequisiti
Prima di iniziare, assicurarsi di:
- Creare un account Azure con una sottoscrizione attiva. Per informazioni dettagliate, vedere Creare un account gratuito.
- Scaricare e installare Python.
- Scaricare e installare Visual Studio Code o un altro IDE che supporta Python.
- Creare una risorsa di Servizi di comunicazione di Azure. Per informazioni dettagliate, vedere Creare una risorsa Servizi di comunicazione di Azure. Per questa esercitazione sono necessari resource_endpoint_name e resource_endpoint_secret .
Firmare una richiesta HTTP con Python
L'autenticazione con chiave di accesso usa una chiave privata condivisa per generare una firma HMAC per ogni richiesta HTTP. Questa firma viene generata con l'algoritmo SHA256 e viene inviata nell'intestazione Authorization
usando lo HMAC-SHA256
schema . Ad esempio:
Authorization: "HMAC-SHA256 SignedHeaders=x-ms-date;host;x-ms-content-sha256&Signature=<hmac-sha256-signature>"
L'oggetto hmac-sha256-signature
è costituito da:
- Verbo HTTP (ad esempio,
GET
oPUT
) - Percorso della richiesta HTTP
- x-ms-date
- Host
- x-ms-content-sha256
Eseguire la configurazione
I passaggi seguenti descrivono come costruire l'intestazione di autorizzazione.
Creare un nuovo script Python
Aprire Visual Studio Code o un altro IDE o un altro editor a scelta e creare un nuovo file denominato sign_hmac_tutorial.py
. Salvare il file in una cartella nota.
Aggiungere le importazioni necessarie
Aggiornare lo sign_hmac_tutorial.py
script con il codice seguente per iniziare.
import base64
import hashlib
import hmac
import json
from datetime import datetime, timezone
from urllib import request
Preparare i dati per la richiesta
Per questo esempio si firmerà una richiesta per creare una nuova identità usando l'API di autenticazione di Servizi di comunicazione (versione 2021-03-07
).
Aggiungere il codice seguente allo sign_hmac_tutorial.py
script.
- Sostituire
resource_endpoint_name
con il valore del nome dell'endpoint della risorsa reale. Questo valore è disponibile nella sezione Panoramica della risorsa Servizi di comunicazione di Azure. È il valore di "Endpoint" dopo "https://". - Sostituire
resource_endpoint_secret
con il valore del segreto dell'endpoint della risorsa reale. Questo valore è disponibile nella sezione Chiavi della risorsa Servizi di comunicazione di Azure. È il valore di "Key" ( primario o secondario).
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")
Creare un hash del contenuto
L'hash del contenuto fa parte della firma HMAC. Usare il codice seguente per calcolare l'hash del contenuto. È possibile aggiungere questo metodo allo 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
Calcolare una firma
Usare il codice seguente per creare un metodo per calcolare la 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
Ottenere il timestamp UTC corrente in base allo standard RFC1123
Usare il codice seguente per ottenere il formato di data desiderato indipendente dalle impostazioni locali.
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)
Creare una stringa di intestazione di autorizzazione
Verrà ora creata la stringa che verrà aggiunta all'intestazione di autorizzazione.
- Preparare i valori per le intestazioni da firmare.
- Specificare il timestamp corrente usando il fuso orario UTC (Coordinated Universal Time).
- Ottenere l'autorità di richiesta (nome host DNS o indirizzo IP e numero di porta).
- Calcolare un hash del contenuto.
- Preparare una stringa per firmare.
- Calcolare la firma.
- Concatenare la stringa, che verrà usata nell'intestazione dell'autorizzazione.
Aggiungere il codice seguente allo 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}"
Aggiungere le intestazioni
Usare il codice seguente per aggiungere le intestazioni necessarie.
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"
Testare il client
Chiamare l'endpoint e controllare la risposta.
req = request.Request(request_uri, content, request_headers, method='POST')
with request.urlopen(req) as response:
response_string = json.load(response)
print(response_string)
Pulire le risorse
Per pulire e rimuovere una sottoscrizione di Servizi di comunicazione, eliminare la risorsa o il gruppo di risorse. Eliminando il gruppo di risorse vengono eliminate anche tutte le altre risorse associate. Altre informazioni sulla pulizia delle risorse Servizi di comunicazione di Azure e sulla pulizia delle risorse Funzioni di Azure.
Passaggi successivi
È anche possibile: