Conceitos comuns

Este artigo fornece conceitos comuns ao desenvolver aplicativos que usam a API REST dos Hubs de Notificação do Azure.

Observação

Para garantir um nível mais alto de segurança, os Hubs de Notificação desabilitarão o suporte para as versões 1.0 e 1.1 do TLS em 30 de abril de 2020. Para obter mais informações, consulte TLS (Transport Layer Security) na documentação dos Hubs de Notificação do Azure.

Analisar cadeia de conexão

Para acessar um hub de notificação, você deve ter duas informações: o nome do hub e uma cadeia de conexão. A cadeia de conexão contém informações sobre o ponto de extremidade do hub e as credenciais de segurança usadas para acessá-lo (para SAS, ele contém um nome de regra e um valor de chave).

O código a seguir analisa a cadeia de conexão para extrair as informações relevantes:

public partial class ConnectionStringUtility
{
    public string Endpoint { get; private set; }
    public string SasKeyName { get; private set; }
    public string SasKeyValue { get; private set; }

    public ConnectionStringUtility(string connectionString)
    {
        //Parse Connectionstring
        char[] separator = { ';' };
        string[] parts = connectionString.Split(separator);
        for (int i = 0; i < parts.Length; i++)
        {
            if (parts[i].StartsWith("Endpoint"))
                Endpoint = "https" + parts[i].Substring(11);
            if (parts[i].StartsWith("SharedAccessKeyName"))
                SasKeyName = parts[i].Substring(20);
            if (parts[i].StartsWith("SharedAccessKey"))
                SasKeyValue = parts[i].Substring(16);
        }
    }
}
var parts = connectionString.split(';');
if (parts.length != 3)
throw "Error parsing connection string";

parts.forEach(function(part) {
if (part.indexOf('Endpoint') == 0) {
endpoint = 'https' + part.substring(11);
} else if (part.indexOf('SharedAccessKeyName') == 0) {
sasKeyName = part.substring(20);
} else if (part.indexOf('SharedAccessKey') == 0) {
sasKeyValue = part.substring(16);
}
});

Criar token de segurança SAS

Para autenticar usando SAS, um cliente deve especificar um token SAS no cabeçalho De autorização de suas solicitações. O token é construído a partir das informações extraídas da cadeia de conexão e da solicitação atual que precisa ser autenticada. O token tem o seguinte formato:

SharedAccessSignature sig=<signature-string>&se=<expiry>&skn=<keyName>&sr=<URL-encoded-resourceURI>

O token refere-se a um keyName (para enviar notificações, você geralmente usa a propriedade DefaultFullSharedAccessSignature que é criada automaticamente em todos os hubs de notificação).

A assinatura do token SAS é computada usando o HMAC-SHA256 de um valor de cadeia de caracteres para assinar com a propriedade PrimaryKey de uma regra de autorização. O valor de cadeia de caracteres para assinar consiste em um URI de recurso e uma expiração, formatada da seguinte maneira:

StringToSign = <resourceURI> + "\n" + expiry;

Use o URI de recurso não codificado para esta operação. O URI do recurso é o URI completo do recurso do Barramento de Serviço ao qual o acesso é solicitado. O formulário é o seguinte:

http://<namespace>.servicebus.windows.net/<hubName>

Por exemplo:

http://contoso.servicebus.windows.net/myHub

A expiração é representada como o número de segundos desde a época 00:00:00 UTC em 1º de janeiro de 1970.

A regra de autorização de acesso compartilhado usada para assinatura deve ser configurada na entidade especificada por esse URI. No exemplo anterior, URI é http://contoso.servicebus.windows.net/myHub ou http://contoso.servicebus.windows.net.

O resourceURI codificado por URL deve ser o mesmo que o URI usado na cadeia de caracteres para assinar durante a computação da assinatura. Ele deve ser codificado por porcentagem e em minúsculas.

O código a seguir, dado um URI de solicitação, cria um token SAS. A versão do Java usa o Apache Commons Codec e a versão do Javascript usa CryptoJS.

public partial class ConnectionStringUtility
{
    public string getSaSToken(string uri, int minUntilExpire)
    {
        string targetUri = Uri.EscapeDataString(uri.ToLower()).ToLower();

        // Add an expiration in seconds to it.
        long expiresOnDate = DateTime.Now.Ticks / TimeSpan.TicksPerMillisecond;
        expiresOnDate += minUntilExpire * 60 * 1000;
        long expires_seconds = expiresOnDate / 1000;
        String toSign = targetUri + "\n" + expires_seconds;

        // Generate a HMAC-SHA256 hash or the uri and expiration using your secret key.
        MacAlgorithmProvider macAlgorithmProvider = MacAlgorithmProvider.OpenAlgorithm(MacAlgorithmNames.HmacSha256);
        BinaryStringEncoding encoding = BinaryStringEncoding.Utf8;
        var messageBuffer = CryptographicBuffer.ConvertStringToBinary(toSign, encoding);
        IBuffer keyBuffer = CryptographicBuffer.ConvertStringToBinary(SasKeyValue, encoding);
        CryptographicKey hmacKey = macAlgorithmProvider.CreateKey(keyBuffer);
        IBuffer signedMessage = CryptographicEngine.Sign(hmacKey, messageBuffer);

        string signature = Uri.EscapeDataString(CryptographicBuffer.EncodeToBase64String(signedMessage));

        return "SharedAccessSignature sr=" + targetUri + "&sig=" + signature + "&se=" + expires_seconds + "&skn=" + SasKeyName;
    }
}
var getSelfSignedToken = function(targetUri, sharedKey, ruleId,
expiresInMins) {
targetUri = encodeURIComponent(targetUri.toLowerCase()).toLowerCase();

// Set expiration in seconds
var expireOnDate = new Date();
expireOnDate.setMinutes(expireOnDate.getMinutes() + expiresInMins);
var expires = Date.UTC(expireOnDate.getUTCFullYear(), expireOnDate
.getUTCMonth(), expireOnDate.getUTCDate(), expireOnDate
.getUTCHours(), expireOnDate.getUTCMinutes(), expireOnDate
.getUTCSeconds()) / 1000;
var tosign = targetUri + '\n' + expires;

// using CryptoJS
var signature = CryptoJS.HmacSHA256(tosign, sharedKey);
var base64signature = signature.toString(CryptoJS.enc.Base64);
var base64UriEncoded = encodeURIComponent(base64signature);

// construct autorization string
var token = "SharedAccessSignature sr=" + targetUri + "&sig="
+ base64UriEncoded + "&se=" + expires + "&skn=" + ruleId;
// console.log("signature:" + token);
return token;
};