일반적인 개념
이 문서에서는 Azure Notification Hubs REST API를 사용하는 애플리케이션을 개발할 때 일반적인 개념을 제공합니다.
참고
더 높은 수준의 보안을 보장하기 위해 Notification Hubs는 2020년 4월 30일에 TLS 버전 1.0 및 1.1에 대한 지원을 사용하지 않도록 설정합니다. 자세한 내용은 Azure Notification Hubs 설명서의 TLS(전송 계층 보안) 를 참조하세요.
연결 문자열 구문 분석
알림 허브에 액세스하려면 허브 이름과연결 문자열이라는 두 가지 정보가 있어야 합니다. 연결 문자열에는 허브의 엔드포인트에 대한 정보와 허브에 액세스하는 데 사용되는 보안 자격 증명이 포함됩니다(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 토큰의 서명은 권한 부여 규칙의 PrimaryKey 속성과 함께 문자열 간 값의 HMAC-SHA256을 사용하여 계산됩니다. 문자열-서명 값은 다음과 같이 형식이 지정된 리소스 URI 및 만료로 구성됩니다.
StringToSign = <resourceURI> + "\n" + expiry;
이 작업에는 인코딩되지 않은 리소스 URI를 사용합니다. 리소스 URI은 액세스를 하려는 Service Bus 리소스의 전체 URI입니다. 양식은 다음과 같습니다.
http://<namespace>.servicebus.windows.net/<hubName>
예를 들면 다음과 같습니다.
http://contoso.servicebus.windows.net/myHub
만료는 1970년 1월 1일 epoch 0시 UTC 이후의 초 수로 표시됩니다.
서명에 사용되는 공유 액세스 권한 부여 규칙은 이 URI에서 지정한 엔터티에 구성되어야 합니다. 이전 예제에서 URI는 또는 http://contoso.servicebus.windows.net
입니다http://contoso.servicebus.windows.net/myHub
.
URL로 인코딩된 resourceURI 는 서명을 계산하는 동안 문자열-서명에 사용되는 URI와 동일해야 합니다. 백분율로 인코딩되고 소문자여야 합니다.
요청 URI가 지정된 다음 코드는 SAS 토큰을 만듭니다. Java 버전은 Apache Commons Codec를 사용하고 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;
};