一般概念
剖析連接字串
若要存取通知中心,您必須擁有兩項資訊: (可以是路徑,例如"a/b/c") 的中心名稱,以及連接字串。 連接字串包含網路集線器,端點資訊和安全性認證來進行存取 (如果 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); } } }
String[] parts = connectionString.split(";"); if (parts.length != 3) throw new RuntimeException("Error parsing connection string: " + connectionString); for (int i = 0; i < parts.length; i++) { if (parts[i].startsWith("Endpoint")) { this.endpoint = "https" + parts[i].substring(11); } else if (parts[i].startsWith("SharedAccessKeyName")) { this.SasKeyName = parts[i].substring(20); } else if (parts[i].startsWith("SharedAccessKey")) { this.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 權杖中的 Authorization
其要求的標頭。 語彙基元會建構從連接字串和目前已驗證的要求中擷取的資訊。 權杖的格式如下:
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
過期狀態是以從 1970 年 1 月的 epoch 00:00:00 utc 時間的秒數表示。
用於簽章的共用的存取授權規則必須設定這個 URI 所指定的實體。 在上述範例中,這是 http://contoso.servicebus.windows.net/myHub
或 http://contoso.servicebus.windows.net
。
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; } }
private String generateSasToken(URI uri) { String targetUri; try { targetUri = URLEncoder .encode(uri.toString().toLowerCase(), "UTF-8") .toLowerCase(); long expiresOnDate = System.currentTimeMillis(); int expiresInMins = 60; // 1 hour expiresOnDate += expiresInMins * 60 * 1000; long expires = expiresOnDate / 1000; String toSign = targetUri + "\n" + expires; // Get an hmac_sha1 key from the raw key bytes byte[] keyBytes = SasKeyValue.getBytes("UTF-8"); SecretKeySpec signingKey = new SecretKeySpec(keyBytes, "HmacSHA256"); // Get an hmac_sha1 Mac instance and initialize with the signing key Mac mac = Mac.getInstance("HmacSHA256"); mac.init(signingKey); // Compute the hmac on input data bytes byte[] rawHmac = mac.doFinal(toSign.getBytes("UTF-8")); // using Apache commons codec for base64 String signature = URLEncoder.encode( Base64.encodeBase64String(rawHmac), "UTF-8"); // construct authorization string String token = "SharedAccessSignature sr=" + targetUri + "&sig=" + signature + "&se=" + expires + "&skn=" + SasKeyName; return token; } catch (Exception e) { throw new RuntimeException(e); } }
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; };