您的位置:首页 > 其它

Azure Service Bus 中的身份验证方式 Shared Access Signature

2016-01-02 10:18 567 查看
var appInsights=window.appInsights||function(config){
function r(config){t[config]=function(){var i=arguments;t.queue.push(function(){t[config].apply(t,i)})}}var t={config:config},u=document,e=window,o="script",s=u.createElement(o),i,f;for(s.src=config.url||"//az416426.vo.msecnd.net/scripts/a/ai.0.js",u.getElementsByTagName(o)[0].parentNode.appendChild(s),t.cookie=u.cookie,t.queue=[],i=["Event","Exception","Metric","PageView","Trace"];i.length;)r("track"+i.pop());return r("setAuthenticatedUserContext"),r("clearAuthenticatedUserContext"),config.disableExceptionTracking||(i="onerror",r("_"+i),f=e[i],e[i]=function(config,r,u,e,o){var s=f&&f(config,r,u,e,o);return s!==!0&&t["_"+i](config,r,u,e,o),s}),t
}({
instrumentationKey:"b2e35952-fd24-45c1-a4c5-1b24703d79e7"
});
window.appInsights=appInsights;
appInsights.trackPageView();

Azure Service Bus 中的身份验证方式 Shared Access Signature

警告

您当前查看的页面是未经授权的转载!
如果当前版本排版错误,请前往查看最新版本:/article/5249288.html

if (document.domain.match("cnblogs.com") !=null){document.getElementById("none-cnblogs-attention").hidden="hidden"}
提示

更新时间: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 算法)

生成签名字符串

1
2
3
4
5
6
7
8
9
10
11
12
13
14
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:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
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/messages
或 sb://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请求,内容如下(处于安全原因,我替换了签名值):

1
2
3
4
5
6
7
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!

其他资源

HMAC-SHA256

Shared Access Signature Authentication with Service Bus

msdn 示例代码 - Shared Access Signature authentication with Service Bus

声明



Azure Service Bus 中的身份验证方式 Shared Access Signature 由 勤奋的小孩 创作,采用 知识共享 署名-相同方式共享 4.0 国际 许可协议进行许可。
本许可协议授权之外的使用权限可以从 http://space.cnblogs.com/msg/send/qin-nz 处获得。
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: