Azure Service Bus 中的身份驗證方式 Shared Access Signature

jopen 8年前發布 | 10K 次閱讀 Windows Azure

提示

本文更新時間:2016年01月01日.

今天踩了一個坑……

在 Azure 的 Service Bus (服務總線) 中,每個請求是需要保護一個驗證信息的。 這個驗證信息可以是SAS,也可以是ACS(已經不建議使用)。

注解

如果是可以安全保存Key的服務器想要訪問 Service Bus,并且不是使用.NET Core,是不需要知道有SAS Token 這種東西存在的。

小技巧

Azure Storage 對于非public的文件方法也是使用這個的思想,但用于簽名的具體參數不同。

Shared Access Signature 機制?

Shared Access Signature ,從名字上不難看出,這是一個通過簽名來共享訪問權限的機制。 在 Service Bus 中,我們有一個名為 RootManageSharedAccessKey 的Key, 這個 Key 擁有這個 Service Bus 的完整訪問權限。 我們可以為每個隊列/主題/事件中心 創建獨立的Key,甚至可以為他們分配不同的權限。

注解

在管理門戶中看到的 Key 一般有兩個, PrimaryKey 和 SecondaryKey ,任意一個都可用。 兩個的目的是方便定期更換密鑰,建議使用 PrimaryKey 。

由于 Service Bus 的發送方可能是終端設備,比如IoT設備等,就這樣把Key下發下去很不安全,因此可以 Shared Access Signature 機制。

當我們需要訪問某個資源,如 https://qinnz.servicebus.windows.net/myeventhub/message 時, 我們用剛剛的key對這個資源和可訪問的有效期進行簽名,并把簽名+資源+有效期三項內容發給服務器,服務器即可進行簽名驗證。

Shared Access Signature 生成過程?

這里,我們就用 RootManageSharedAccessKey 密鑰進行簽名。

  • 對資源Uri進行encode,資源Uri可以是請求的資源或者它的父資源。
  • 得到過期時間的Unix時間戳(Azure Storage 使用的是人可識別的日期格式)
  • 將Key使用 UTF-8 編碼轉換為字節數組,作為簽名密鑰
  • 對資源uri和時間戳進行簽名(使用 HMAC-SHA256 算法)
  • 生成簽名字符串
public class SasToken
    {
        public static string Generator(string uri, DateTimeOffset expiryTime, string keyName, string keyValue)
        {
            string uriEncoded = Uri.EscapeDataString(uri.ToString());
            long expiry = expiryTime.ToUnixTimeSeconds();  //Only available on .Net 4.6
            byte[] key = Encoding.UTF8.GetBytes(keyValue);
            var hmac = new HMACSHA256(key);
            string stringToSign = uriEncoded + "\n" + expiry.ToString();
            string signature = Convert.ToBase64String(hmac.ComputeHash(Encoding.UTF8.GetBytes(stringToSign)));
            Debug.WriteLine(stringToSign);
            return $"SharedAccessSignature sr={uriEncoded}&sig={Uri.EscapeDataString(signature)}&se={expiry}&skn={keyName}";
        }
    }

嗯,上面就是我自己實現的……坑就在于第7行……

在微軟官方文檔中,他們也以為是 base64 編碼的,我剛剛在Github上提交了這個 issue

事實上,微軟官方是有C#類庫來做這件事的(下面第15行); 我自己實現僅為了能在別的平臺上能用。 下面說說官方給出的實現代碼和我的代碼做比較,注意替換自己的key和keyName:

using System;
using Microsoft.ServiceBus;

namespace SharedAccessSignatureTokenGenerator
{
    class Program
    {
        private static string resource = "<your-resource>";
        private static string key = "<your-key-for-RootManageSharedAccessKey>";
        private static string keyName = "RootManageSharedAccessKey";

        static void Main(string[] args)
        {
            // Get Token using  Microsoft.ServiceBus.SharedAccessSignatureTokenProvider.GetSharedAccessSignature
            var token = SharedAccessSignatureTokenProvider.GetSharedAccessSignature(keyName, key, resource, new TimeSpan(24, 0, 0));

            //Get Token using my SasToken.Generator
            long se = long.Parse(token.Substring(token.IndexOf("se=") + 3, 10));
            var mytoken = SasToken.Generator(resource, new DateTimeOffset(2050, 1, 1, 0, 0, 0, new TimeSpan()), keyName, key);

            Console.WriteLine(mytoken);
            Console.WriteLine(token);
        }
    }
}

注解

由于我使用的 Uri.EscapeDataString 返回的是大寫字母,造成簽名值不一樣;不過因為sr同樣不一樣,并沒有什么影響。

可以使用 uriEncoded=uriEncoded.ToLower(); 使得兩種方法簽名一致。

訪問測試?

現在,就可以向 Service Bus 發送消息了。

注解

Event Hub 的API可以參考 這里

例如我們可以向 sb://qinnz.servicebus.windows.net/mail/messages 發送消息, 可以指定 sr 為 sb://qinnz.servicebus.windows.net/mail/messagessb://qinnz.servicebus.windows.net (如果key的權限足夠,那么此時的SAS具有整個servicebus的訪問權限) 我們需要設定SAS的過期時間,已經你使用的密鑰的名字,使Azure可以在服務器端驗證簽名。

最終,我們生成下面的字符串作為HTTP請求的Authorization請求頭。

SharedAccessSignature sr=sb%3A%2F%2Fqinnz.servicebus.windows.net%2Fmail%2Fmessages
&sig=Augn3gnz4PEz%2Faaaaaaaaaaaaaaaaaaaacr%2B4vd2tWE%3D
&se=2000000000&skn=RootManageSharedAccessKey

下面我就用 Fiddler 模擬發送POST請求,內容如下(處于安全原因,我替換了簽名值):

POST https://qinnz.servicebus.windows.net/mail/messages
Authorization: SharedAccessSignature sr=sb%3A%2F%2Fqinnz.servicebus.windows.net%2Fmail%2Fmessages&sig=Augn3gnz4PEz%2Faaaaaaaaaaaaaaaaaaaacr%2B4vd2tWE%3D&se=2000000000&skn=RootManageSharedAccessKey
Content-Type: application/atom+xml;type=entry;charset=utf-8
Host: qin-nz.servicebus.windows.net
Content-Length: 5

hello!

來自: http://www.cnblogs.com/qin-nz/p/azure-service-bus-shared-access-signature-token.html

 本文由用戶 jopen 自行上傳分享,僅供網友學習交流。所有權歸原作者,若您的權利被侵害,請聯系管理員。
 轉載本站原創文章,請注明出處,并保留原始鏈接、圖片水印。
 本站是一個以用戶分享為主的開源技術平臺,歡迎各類分享!