Общие понятия
В этой статье приведены общие понятия при разработке приложений, использующих REST API Центров уведомлений Azure.
Примечание
Чтобы обеспечить более высокий уровень безопасности, Центры уведомлений отключают поддержку TLS версий 1.0 и 1.1 30 апреля 2020 г. Дополнительные сведения см. в разделе Tls документации по Центрам уведомлений Azure.
Анализ строки подключения
Для доступа к центру уведомлений необходимо иметь два элемента информации: имя концентратора и строку подключения. Строка подключения содержит сведения о конечной точке центра и учетные данные безопасности, используемые для доступа к ней (для SAS она содержит имя правила и значение ключа).
Следующий код анализирует строку подключения для извлечения соответствующих сведений:
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);
}
});
Создание маркера безопасности SAS
Для проверки подлинности с помощью SAS клиент должен указать маркер SAS в заголовке авторизации своих запросов. Маркер создается на основе сведений, извлеченных из строки подключения, и текущего запроса, который должен пройти проверку подлинности. Маркер имеет следующую форму:
SharedAccessSignature sig=<signature-string>&se=<expiry>&skn=<keyName>&sr=<URL-encoded-resourceURI>
Маркер ссылается на keyName (для отправки уведомлений обычно используется свойство DefaultFullSharedAccessSignature , которое создается автоматически во всех центрах уведомлений).
Подпись маркера SAS вычисляется с помощью HMAC-SHA256 значения типа "строка — знак" со свойством PrimaryKey правила авторизации. Значение типа "строка — знак" состоит из URI ресурса и срока действия в следующем формате:
StringToSign = <resourceURI> + "\n" + expiry;
Для этой операции используйте некодированный URI ресурса. URI ресурса — это полный URI ресурса служебной шины, к которому запрашивается доступ. Форма выглядит следующим образом:
http://<namespace>.servicebus.windows.net/<hubName>
Пример:
http://contoso.servicebus.windows.net/myHub
Срок действия исчисляется в количестве секунд с момента начала эры Unix, т. е. с 00:00:00 1 января 1970 г. (в формате UTC).
Правило авторизации общего доступа, используемое для подписывания, должно быть настроено для сущности, указанной в этом URI. В предыдущем примере универсальный код ресурса (URI) имеет значение http://contoso.servicebus.windows.net/myHub
или http://contoso.servicebus.windows.net
.
URI ресурса в кодировке URL-адреса должен совпадать с универсальным кодом ресурса (URI), используемым в строке для подписи во время вычисления подписи. Оно должно быть закодировано в процентах и в нижнем регистре.
Следующий код, при использовании универсального кода ресурса (URI) запроса, создает маркер SAS. В версии Java используется кодек Apache Commons, а в версии JavaScript — 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;
};