为Amazon Kinesis Signaling Channel C#创建一个预签名URL

问题描述

我正在尝试使用C#websockets连接到Amazon Kinesis信令渠道。

为此,我需要一个预签名的url,但是无论我怎样尝试,我都会收到403禁止响应。

我知道我的凭据是正确的,因为我已经使用测试页进行了检查。 (https://awslabs.github.io/amazon-kinesis-video-streams-webrtc-sdk-js/examples/index.html

我什至设法获取页面生成的签名URL并成功连接到它。 但是,我自己对URL进行签名的所有尝试都失败了。

谁能告诉我我做错了什么? 这是我所拥有的:

using System;
using System.Security.Cryptography;
using System.Text;
using Amazon.Runtime;
using Amazon.SecurityToken.Model;
using Amazon.Util;

namespace AwsIotMqttWebSocketSigner
{
    public static class sigv4Utils
    {
        private static readonly Encoding m_encoding = Encoding.UTF8;

        private static StringBuilder AppendHex(this StringBuilder sb,byte[] bytes)
        {
            for (int i = 0; i < bytes.Length; i++)
            {
                sb.AppendFormat(bytes[i].ToString("x2"));
            }
            return sb;
        }

        private static StringBuilder AppendSha256Hex(this StringBuilder sb,string data)
        {
            byte[] bytes = m_encoding.GetBytes(data);
            using (SHA256 algo = SHA256.Create())
            {
                byte[] hash = algo.ComputeHash(bytes);
                sb.AppendHex(hash);
            }
            return sb;
        }

        private static byte[] GetHmac(string key,string data)
        {
            byte[] keyBytes = m_encoding.GetBytes(key);
            return GetHmac(keyBytes,data);
        }

        private static byte[] GetHmac(byte[] key,string data)
        {

            using (HMACSHA256 kha = new HMACSHA256(key))
            {
                byte[] dataBytes = m_encoding.GetBytes(data);
                byte[] hash = kha.ComputeHash(dataBytes);
                return hash;
            }
        }

        private static byte[] GetSignatureKey(string key,string date,string region,string service)
        {

            byte[] kDate = GetHmac("AWS4" + key,date);
            byte[] kRegion = GetHmac(kDate,region);
            byte[] kService = GetHmac(kRegion,service);
            byte[] kCredentials = GetHmac(kService,"aws4_request");
            return kCredentials;
        }
        static string CanonicalResourcePath(Uri endpointUri)
        {
            if (string.IsNullOrEmpty(endpointUri.AbsolutePath))
                return "/";

            // encode the path per RFC3986
            return AWSSDKUtils.UrlEncode(endpointUri.AbsolutePath,true);
        }

        public const string EMPTY_BODY_SHA256 = "e3b0c44298fc1c149afbf4c8996fb92427ae41e4649b934ca495991b7852b855";

        internal static string GetSignedUri(
                Uri uri,Credentials credentials,string channelARN
            )
        {

            DateTime utcNow = CorrectClockSkew.GetCorrectedUtcNowForEndpoint(region);
            string datetime = utcNow.ToString("yyyyMMddTHHmmssZ");
            string date = datetime.Substring(0,8);

            const string service = "kinesisvideo";
            const string method = "GET";
            const string algorithm = "AWS4-HMAC-SHA256";
            string protocol = uri.Scheme;
            string host = uri.Host;
            string credentialScope = date + "/" + region + "/" + service + "/" + "aws4_request";

            var canonicalQuerystring = new StringBuilder(800)
                .Append("X-Amz-Algorithm=")
                .Append(algorithm)
                .Append("&X-Amz-ChannelARN=")
                .Append(AWSSDKUtils.UrlEncode(channelARN,false))
                .Append("&X-Amz-Credential=")
                .Append(AWSSDKUtils.UrlEncode(credentials.AccessKeyId,false))
                .Append("%2F")
                .Append(AWSSDKUtils.UrlEncode(credentialScope,false))
                .Append("&X-Amz-Date=")
                .Append(datetime)
                .Append("&X-Amz-Expires=299");

            if (string.IsNullOrEmpty(credentials.SessionToken) == false)
            {
                canonicalQuerystring.Append("&X-Amz-Security-Token=")
                .Append(AWSSDKUtils.UrlEncode(credentials.SessionToken,false));
            }

            canonicalQuerystring.Append("&X-Amz-SignedHeaders=host;x-amz-date");

            var canonicalRequest = new StringBuilder(350)
                .Append(method)
                .Append('\n')
                .Append(CanonicalResourcePath(uri))
                .Append('\n')
                .Append(canonicalQuerystring)
                .Append("\n")
                .Append("\nhost:")
                .Append(host)
                .Append("\nx-amz-date:")
                .Append(datetime)
                .Append("\n\nhost;x-amz-date\n")
                .Append(EMPTY_BODY_SHA256)//.AppendSha256Hex(String.Empty)
                .ToString();

            var canonicalRequestStr = canonicalRequest.ToString();

            var stringToSign = new StringBuilder(200)
                .Append(algorithm)
                .Append('\n')
                .Append(datetime)
                .Append('\n')
                .Append(credentialScope)
                .Append('\n')
                .AppendSha256Hex(canonicalRequestStr)
                .ToString();

            byte[] signingKey = GetSignatureKey(credentials.SecretAccessKey,date,region,service);
            byte[] signatureBytes = GetHmac(signingKey,stringToSign);

            canonicalQuerystring
                .Append("&X-Amz-Signature=")
                .AppendHex(signatureBytes);

            string requestUrl = protocol + "://" + host + uri.AbsolutePath + "?" + canonicalQuerystring;
            return requestUrl;
        }
    }
}

解决方法

暂无找到可以解决该程序问题的有效方法,小编努力寻找整理中!

如果你已经找到好的解决方法,欢迎将解决方案带上本链接一起发送给小编。

小编邮箱:dio#foxmail.com (将#修改为@)