在GoLang中生成CosmosDB身份验证令牌

时间:2017-10-07 21:04:07

标签: go azure-cosmosdb

我正在尝试按照此处的说明生成CosmosDb Auth令牌: https://docs.microsoft.com/en-us/rest/api/documentdb/access-control-on-documentdb-resources

这是我在GoLang中的实现(我用上面文档中“示例编码”部分中的文字值替换了所有参数):

import(
    "crypto/hmac"
    "crypto/sha256"
    "encoding/base64"
    "net/url")

func generateAuthToken(
    verb string,
    resourceType string,
    resourceId string,
    date string,
    base64Key string) string {

    // Example Key
    base64Key := "dsZQi3KtZmCv1ljt3VNWNm7sQUF1y5rJfC6kv5JiwvW0EndXdDku/dkKBp8/ufDToSxLzR4y+O/0H/t4bQtVNw=="
    msg := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n",
        "get",                            //verb
        "dbs",                            //resourceId
        "dbs/todolist",                   //resourceLink
        "thu, 27 apr 2017 00:51:12 gmt",  //RFC1123 date
        "")

    hasher := hmac.New(sha256.New, []byte(base64Key))
    hasher.Write([]byte(msg))
    signature := base64.StdEncoding.EncodeToString(hasher.Sum(nil))

    authHeader := fmt.Sprintf("type=master&ver=1.0&sig=%s", signature)
    return url.QueryEscape(authHeader)
}

我还从链接中获取了C#示例,并使用与参考相同的参数运行它。

这是我从C#实现中获得的(参考):

"type%3Dmaster%26ver%3D1.0%26sig%3DSGWmGNFZlBH%2Bt9QCvuMy%2FVsbBAOKLbxsgy3Z7aG0PdA%3D"

这是我从GoLang实施中得到的结果:

"type%3Dmaster%26ver%3D1.0%26sig%3Dwst1NDxfOeoYMurn69DgZtJUQOrgxFz%2Bp6A2vKnXxEI%3D"

显然我在GoLang实现中做错了,因为两者不相同(可能误用了散列库?)

为便于参考,这里是C#实现:

static void Main(string[] args) {
      string token = GenerateAuthToken(
             "get",
             "dbs",
             "dbs/todolist",
             "thu, 27 apri 2017 00:51:12 gmt", 
             "dsZQi3KtZmCv1ljt3VNWNm7sQUF1y5rJfC6kv5JiwvW0EndXdDku/dkKBp8/ufDToSxLzR4y+O/0H/t4bQtVNw==",
             "master",
             "1.0");
}

static string GenerateAuthToken(string verb, string resourceType, string resourceId, string date, string key, string keyType, string tokenVersion)
{
      var hmacSha256 = new System.Security.Cryptography.HMACSHA256 { Key = Convert.FromBase64String(key) };

      verb = verb ?? "";
      resourceType = resourceType ?? "";
      resourceId = resourceId ?? "";

      string payLoad = string.Format(System.Globalization.CultureInfo.InvariantCulture, "{0}\n{1}\n{2}\n{3}\n{4}\n",
            verb.ToLowerInvariant(),
            resourceType.ToLowerInvariant(),
            resourceId,
            date.ToLowerInvariant(),
            "");

      byte[] hashPayLoad = hmacSha256.ComputeHash(System.Text.Encoding.UTF8.GetBytes(payLoad));
      string signature = Convert.ToBase64String(hashPayLoad);

      return System.Net.WebUtility.UrlEncode(String.Format(System.Globalization.CultureInfo.InvariantCulture, "type={0}&ver={1}&sig={2}",
            keyType,
            tokenVersion,
            signature));
}

1 个答案:

答案 0 :(得分:4)

这让我找到了比我希望的更长的时间。有一个明显的问题,你不是base64解码这一行的密钥

hasher := hmac.New(sha256.New, []byte(base64Key))

您应该执行类似

的操作
hmacKey, _ := base64.StdEncoding.DecodeString(base64Key)
// handle error
hasher := hmac.New(sha256.New, hmacKey)

但即使这样也没有解决它。直到我终于弄清楚这种差异

C# "thu, 27 apri 2017 00:51:12 gmt"
Go "thu, 27 apr 2017 00:51:12 gmt" 

这有效

func generateAuthToken(
    verb string,
    resourceType string,
    resourceId string,
    date string,
    base64Key string) string {

    msg := fmt.Sprintf("%s\n%s\n%s\n%s\n%s\n",
        verb,
        resourceType,
        resourceId,
        date,
        "")

    hmacKey, _ := base64.StdEncoding.DecodeString(base64Key)
    // handle error
    hasher := hmac.New(sha256.New, hmacKey)
    hasher.Write([]byte(msg))
    signature := base64.StdEncoding.EncodeToString(hasher.Sum(nil))

    authHeader := fmt.Sprintf("type=master&ver=1.0&sig=%s", signature)
    return url.QueryEscape(authHeader)
}

这是一个Go Playground Link

因此,Go版本几乎是正确的(除了密钥),C#部分几乎是正确的(非RFC1123格式除外)。