Garmin Api OAuth 在 C# 中签署 HMACSHA1

问题描述

我从 apis.garmin.com(端点 https://apis.garmin.com/wellness-api/rest/activityFile)下载活动。我有一个使用 .net framework 4.7 的控制台应用程序。在 C# 中。

garmin api 上的请求必须使用 OAuth 签名。不幸的是,我们发送到 garmin api 的每个请求都会收到一个 http 代码 401(未经授权)作为响应。

Garmin 支持人员给了我一个如何在 PHP 中创建签名的示例。但是,我无法在 C# 中重写此代码

我认为问题在于创建signedEncoded,但我不知道我做错了什么。 PHP 示例:

//sample callbackUrl = 'https://healthapi.garmin.com/wellness-api/rest/activityFile?id=32368310271'
$requestBaseUrl = 'https://healthapi.garmin.com/wellness-api/rest/activityFile'; //this is the base URL needed for signature generation,notice there are no parameters (no id)
$id = 32368310271; //this is the id from the sample callbackUrl (activityId)
$oauth_timestamp = time();
$oauth_nonce = time();
$oauth_token = "XXXXXXXXXXX";
$oauth_token_secret= "XXXXXXXXXX";
$oauth_consumer_key = "XXXXXXXXXXX";
$oauth_consumer_secret = "XXXXXXXXXXXXX";
$oauth_signatureMethod = "HMAC-SHA1";
$oauth_version = "1.0";
$base_signature = "GET&" . rawurlencode($requestBaseUrl) ."&" .
    rawurlencode("id=$id" . "&oauth_consumer_key=$oauth_consumer_key"
        . "&oauth_nonce=$oauth_nonce"
        . "&oauth_signature_method=$oauth_signatureMethod"
        . "&oauth_timestamp=$oauth_timestamp"
        . "&oauth_token=$oauth_token"
        . "&oauth_version=$oauth_version");
echo "base_signature: $base_signature \n<br>";
$oauthSig = hash_hmac("SHA1",$base_signature,$oauth_consumer_secret . "&" . $oauth_token_secret,false);
$oauthSig = rawurlencode(base64_encode(pack('H*',$oauthSig)));
echo $oauthSig."<br>";

来自 Garmin 的 PHP 结果: base_signature:GET&HTTPS%3A%2F%2Fapis.garmin.com%2Fwellness-API%2Frest%2FactivityFile&ID%3D185442821846%26oauth_consumer_key%3DXXXXXXXXXXX%26oauth_nonce%3D1622269862%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1622269862%26oauth_token%3DXXXXXXXXXXX%26oauth_version%3D1。 0

OAuth 签名未编码:88913f4d910a3eef46582e2511724dbf69a79f51 OAuth Sig 编码:iJE%2FTZEKPu9GWC4lEXJNv2mnn1E%3D

我的 C# 代码

using System.Diagnostics;
using System.IO;
using System.Net;
using System.Security.Cryptography;
using System.Text;
using System.Linq;
namespace OAuthTest
{
    class Program
    {
        void Main()
        {
            try
            {
                string oauthToken = "XXXXXXXXXXX";
                string consumerKey = "XXXXXXXXXXX";
                string consumerSecret = "XXXXXXXXXXX";
                string oauthTokenSecret = "XXXXXXXXXXX";
                // basesignature I have the same as from garmin example
                var baseSignature = "GET&https%3A%2F%2Fapis.garmin.com%2Fwellness-api%2Frest%2FactivityFile&id%3D185442821846%26oauth_consumer_key%3D3DXXXXXXXXXXX%26oauth_nonce%3D1622269862%26oauth_signature_method%3DHMAC-SHA1%26oauth_timestamp%3D1622269862%26oauth_token%3DXXXXXXXXXXX%26oauth_version%3D1.0";
                var key = EscapeUriDataStringRfc3986(consumerSecret) + "&" + EscapeUriDataStringRfc3986(oauthTokenSecret);
                var keyBytes = Encoding.ASCII.GetBytes(key);
                var baseSignatureBytes = Encoding.ASCII.GetBytes(baseSignature);

                MemoryStream stream = new MemoryStream(baseSignatureBytes);
                string signedEncoded;
                using (var hmacsha1 = new HMACSHA1(keyBytes))
                {
                    var signedBytes = hmacsha1.ComputeHash(stream);
                    signedEncoded = signedBytes.Aggregate("",(s,e) => s + String.Format("{0:x2}",e),s => s);
                }

                var httpWebRequest = (HttpWebRequest)WebRequest.Create("https://apis.garmin.com/wellness-api/rest/activityFile");
                httpWebRequest.Method = "GET";
                var header =
                        "OAuth " +
                        "oauth_nonce=" + SimpleQuote("1622269862") + "," +
                        "oauth_signature=" + SimpleQuote(signedEncoded) + "," +
                        "oauth_token=" + SimpleQuote(oauthToken) + "," +
                        "oauth_consumer_key=" + SimpleQuote(consumerKey) + "," +
                        "oauth_timestamp=" + SimpleQuote("1622269862") + "," +
                        "oauth_signature_method=" + SimpleQuote("HMAC-SHA1") + "," +
                        "oauth_version=" + SimpleQuote("1.0");
                httpWebRequest.Headers.Add(HttpRequestHeader.Authorization,header);
                var response = httpWebRequest.GetResponse();        // throw exception 401

                var responsestream = response.GetResponseStream();
                using (responsestream)
                {
                    var reader = new StreamReader(responsestream);
                    var result = reader.ReadToEnd();
                    Debug.WriteLine(result);
                }
            }
            catch (Exception ex)
            {
                Debug.WriteLine(ex.ToString());
            }
        }

        private string SimpleQuote(string s) { return '"' + s + '"'; }

        private readonly string[] UriRfc3986CharsToEscape = new[] { "!","*","'","(",")" };

        private string EscapeUriDataStringRfc3986(string value)
        {

            StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value));
            for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++)
            {
                escaped.Replace(UriRfc3986CharsToEscape[i],Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
            }
            return escaped.ToString();
        }
    }
}

解决方法

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

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

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