C# PUT 端点使用 HMACAuthentication 接收空参数

C# PUT Endpoint receives null argument with HMACAuthentication

我正在尝试从我的 Python 客户端调用我的 C#.NET api 端点。

以下两个代码块工作正常:

# Python Client
endpoint = "http://localhost:12345/api/myController/hmacTestPut"
data = {"type": "my_type", "state": "my_state"}
headers = calc_hmac(...)
r = requests.put(url=endpoint, json=data, headers=headers)

// C# Endpoint
[HttpPut]
[Route("api/myController/hmacTestPut")]
//[HMACAuthentication]
public IHttpActionResult HMACTestPut(MyDTO obj)
{
    return Ok(obj)
}

但是,当我在 C# 端点上包含 HMACAuthentication 属性时,MyDTO objnull


由于在这两种情况下都命中了端点,我相信我的 HMACAuthenticationAttribute 是正确的。

包括 [FromBody] 似乎没有任何影响。

为什么将 HMACAuthentication 添加到端点会阻止接收正文内容?

以防其他人遇到这个问题,这个问题(显然)与 HMAC 相关。

在我的 HMACAuthenticationAttribute 中,在我的 ComputeHash() 函数中,这是我计算请求正文哈希值的地方(如 POST 或 PUT 正文)。

下面是问题所在,将 HttpContent 读取到 MemoryStream 会使请求的 HttpContent 为空,实际端点无法读取任何内容:

var ms = new MemoryStream();
await httpContent.copyToAsync(ms);
ms.Seek(0, SeekOrigin.Begin);
var content = ms.ToArray();
byte[] hash = md5.ComputeHash(content)

解决方案 是改变我们读取 HttpRequest 内容的方式:

var content = await httpContent.ReadAsByteArrayAsync().ConfigureAwait(false);
byte[] hash = md5.ComputeHash(content)

下面是完整的简化函数,希望对大家有所帮助。

private static async Task<byte[]> ComputeHash(HttpContent httpContent)
{
    using (MD5 md5 = MD5.Create())
    {
        byte[] hash = null;
        var content = await httpContent.ReadAsByteArrayAsync().ConfigureAwait(false);

        if (content.Length != 0)
        {
            hash = md5.ComputeHash(content);
        }

        return hash;
    }
}