C# Withings API-签名无效
我正试图通过oauth(.net core C#)访问我的Withings/Nokia scales数据 有关说明,请访问: 以下是API指南: 我已经完成了第1部分-我得到了一个认证令牌和密码 第2部分-我已手动检索到授权我的应用程序使用我的withings scales数据的代码-即作为回调结果的身份验证代码(通过API开发者页面)。我想这只需要做一次就可以永久授权我的应用程序访问。我已将此值硬编码到我的代码中,并在重新授权应用程序时进行更新 现在我陷入第3部分-获取访问令牌/密码。 错误=无效签名 (使用上面的页面,我已经能够检索到我4年的量表数据,因此我知道它应该可以工作) 我的基本签名与上面的API测试页面相同(除了nonce、签名和时间戳) 我的url与上面的API测试页面相同(除了nonce和timestamp) 对我来说,谜团是为什么这适用于第1部分而不是第3部分。 是错误的代码,还是在发出请求之前必须针对应用程序/用户数据授权请求令牌? 但我肯定不必每次都与用户重新授权 我最初弄糟了第1部分,并给出了一个无效的签名错误-这显然是签名的问题-但我已经重新检查了第3部分中的签名,它是好的C# Withings API-签名无效,c#,oauth,asp.net-core-mvc,nokia,withings,C#,Oauth,Asp.net Core Mvc,Nokia,Withings,我正试图通过oauth(.net core C#)访问我的Withings/Nokia scales数据 有关说明,请访问: 以下是API指南: 我已经完成了第1部分-我得到了一个认证令牌和密码 第2部分-我已手动检索到授权我的应用程序使用我的withings scales数据的代码-即作为回调结果的身份验证代码(通过API开发者页面)。我想这只需要做一次就可以永久授权我的应用程序访问。我已将此值硬编码到我的代码中,并在重新授权应用程序时进行更新 现在我陷入第3部分-获取访问令牌/密码。 错
private const string AUTH_VERSION = "1.0";
private const string SIGNATURE_METHOD = "HMAC-SHA1";
private const string BASE_URL_REQUEST_AUTH_TOKEN = "https://developer.health.nokia.com/account/request_token";
private const string BASE_URL_REQUEST_ACCESS_TOKEN = "https://developer.health.nokia.com/account/access_token";
谢谢,丹。解决了-这是我理解oauth如何工作的一个问题 步骤1获取令牌(这允许您根据api帐户应用程序发出请求) 步骤2-创建一个URL(使用上面的2分钟令牌),重定向用户以授权您的Withings api应用程序使用特定用户的帐户。在传递令牌时返回相同的令牌-但现在将允许它在步骤3中发出请求 步骤3-请求访问令牌-这将为您提供一个令牌和秘密字符串,允许您继续访问此用户的帐户(对于您的api帐户应用程序) 步骤4请求数据-方法与前面所有步骤类似-非常简单。返回一个很长的数据字符串。尽可能地阅读API文档-这就是我将要做的,因为我有大约4/5年的“有趣”体重数据 我在执行步骤1,然后执行步骤3,认为从步骤2返回的代码(没有注意到它与放入的代码相同)可以存储并用于步骤3,而无需重新授权 实际上,您可以(以及我所做的)按照API演示接口在步骤3中生成身份验证令牌和密码,这就是继续请求数据所需的全部内容。您只需要用户授权一次,并根据用户帐户/某种存储存储步骤3身份验证令牌/密码 还请注意,您可以调用通知-新权重会触发您的网站自动刷新数据。如果您只想登录并查看最新数据,而不需要手动触发数据刷新/造成进一步延迟,这将非常好 请注意,API有过滤选项,因此请确保您仔细阅读了这些选项 以下是一些可能有用的(基本)代码:
public async Task<string> GetData_BodyMeasures()
{
string rawdata = "";
try
{
string random = GetRandomString();
string timestamp = GetTimestamp();
string baseSignature = GetDataSignature_BodyMeasure(random, timestamp);
string hashSignature = ComputeHash(baseSignature, CONSUMER_SECRET, ACCESS_OAUTH_TOKEN_SECRET);
string codeSignature = UrlEncode(hashSignature);
string requestUrl = GetData_BodyMeasure_Url(codeSignature, random, timestamp);
HttpResponseMessage response = await client.GetAsync(requestUrl);
string responseBodyAsText = await response.Content.ReadAsStringAsync();
rawdata = responseBodyAsText;
}
catch (Exception ex)
{
}
return rawdata;
}
private string GetDataSignature_BodyMeasure(string random, string timestamp)
{
var urlDict = new SortedDictionary<string, string>
{
{ "oauth_consumer_key", CONSUMER_KEY},
{ "oauth_nonce", random},
{ "oauth_signature_method", SIGNATURE_METHOD},
{ "oauth_timestamp", timestamp},
{ "oauth_token", ACCESS_OAUTH_TOKEN },
{ "oauth_version", AUTH_VERSION},
{ "userid", USER_ID }
};
StringBuilder sb = new StringBuilder();
sb.Append("GET&" + UrlEncode(BASE_URL_REQUEST_BODY_MEASURE) + "&action%3Dgetmeas");
int count = 0;
foreach (var urlItem in urlDict)
{
count++;
if (count >= 1) sb.Append(UrlEncode("&"));
sb.Append(UrlEncode(urlItem.Key + "=" + urlItem.Value));
}
return sb.ToString();
}
private string GetData_BodyMeasure_Url(string signature, string random, string timestamp)
{
var urlDict = new SortedDictionary<string, string>
{
{ "action", "getmeas"},
{ "oauth_consumer_key", CONSUMER_KEY},
{ "oauth_nonce", random},
{ "oauth_signature", signature },
{ "oauth_signature_method", UrlEncode(SIGNATURE_METHOD)},
{ "oauth_timestamp", timestamp},
{ "oauth_token", ACCESS_OAUTH_TOKEN },
{ "oauth_version", AUTH_VERSION},
{ "userid", USER_ID }
};
StringBuilder sb = new StringBuilder();
sb.Append(BASE_URL_REQUEST_BODY_MEASURE + "?");
int count = 0;
foreach (var urlItem in urlDict)
{
count++;
if (count >= 1) sb.Append("&");
sb.Append(urlItem.Key + "=" + urlItem.Value);
}
return sb.ToString();
}
public异步任务GetData\u BodyMeasures()
{
字符串rawdata=“”;
尝试
{
string random=GetRandomString();
字符串timestamp=GetTimestamp();
string baseSignature=GetDataSignature\u BodyMeasure(随机,时间戳);
string hashSignature=ComputeHash(baseSignature、CONSUMER\u SECRET、ACCESS\u OAUTH\u TOKEN\u SECRET);
字符串codeSignature=UrlEncode(hashSignature);
string requestUrl=GetData\u BodyMeasure\u Url(代码签名、随机、时间戳);
HttpResponseMessage response=wait client.GetAsync(requestUrl);
string responseBodyAsText=等待响应.Content.ReadAsStringAsync();
rawdata=responseBodyAsText;
}
捕获(例外情况除外)
{
}
返回原始数据;
}
私有字符串GetDataSignature\u BodyMeasure(字符串随机,字符串时间戳)
{
var urlDict=新分类词典
{
{“oauth_consumer_key”,consumer_key},
{“oauth_nonce”,random},
{“oauth_签名方法”,签名方法},
{“oauth_timestamp”,timestamp},
{“oauth_令牌”,访问oauth_令牌},
{“oauth_版本”,AUTH_版本},
{“userid”,USER_ID}
};
StringBuilder sb=新的StringBuilder();
sb.Append(“GET&”+UrlEncode(BASE\u URL\u REQUEST\u BODY\u MEASURE)+“&action%3Dgetmeas”);
整数计数=0;
foreach(urlDict中的变量urleItem)
{
计数++;
如果(计数>=1)sb.Append(UrlEncode(&));
sb.Append(UrlEncode(urlItem.Key+“=”+urlItem.Value));
}
使某人返回字符串();
}
私有字符串GetData\u BodyMeasure\u Url(字符串签名、字符串随机、字符串时间戳)
{
var urlDict=新分类词典
{
{“行动”,“getmeas”},
{“oauth_consumer_key”,consumer_key},
{“oauth_nonce”,random},
{“oauth_签名”,签名},
{“oauth_签名_方法”,UrlEncode(签名_方法)},
{“oauth_timestamp”,timestamp},
{“oauth_令牌”,访问oauth_令牌},
{“oauth_版本”,AUTH_版本},
{“userid”,USER_ID}
};
StringBuilder sb=新的StringBuilder();
sb.追加(基\ URL \请求\正文\度量+“?”);
整数计数=0;
foreach(urlDict中的变量urleItem)
{
计数++;
如果(计数>=1)某人追加(&);
某人上诉
public async Task<OAuthAccessToken> GetOAuthAccess(OAuthToken authToken)
{
OAuthAccessToken token = new OAuthAccessToken();
try
{
string random = GetRandomString();
string timestamp = GetTimestamp();
string baseSignature = GetOAuthAccessSignature(authToken, random, timestamp);
string hashSignature = ComputeHash(baseSignature, CONSUMER_SECRET, authToken.OAuth_Token_Secret);
string codeSignature = UrlEncode(hashSignature);
string requestUrl = GetOAuthAccessUrl(authToken, codeSignature, random, timestamp);
HttpResponseMessage response = await client.GetAsync(requestUrl);
string responseBodyAsText = await response.Content.ReadAsStringAsync();
string[] parameters = responseBodyAsText.Split('&');
token.OAuth_Token = parameters[0].Split('=')[1].ToString();
token.OAuth_Token_Secret = parameters[1].Split('=')[1].ToString();
}
catch (Exception ex)
{
}
return token;
}
private string GetOAuthAccessSignature(OAuthToken authToken, string random, string timestamp)
{
var urlDict = new SortedDictionary<string, string>
{
//{ "oauth_consumer_key", CONSUMER_KEY},
{ "oauth_nonce", random},
{ "oauth_signature_method", UrlEncode(SIGNATURE_METHOD)},
{ "oauth_timestamp", timestamp},
{ "oauth_token", END_USER_AUTHORISATION_REQUEST_TOKEN },
{ "oauth_version", AUTH_VERSION}
};
StringBuilder sb = new StringBuilder();
sb.Append("GET&" + UrlEncode(BASE_URL_REQUEST_ACCESS_TOKEN) + "&oauth_consumer_key%3D" + CONSUMER_KEY);
int count = 0;
foreach (var urlItem in urlDict)
{
count++;
if (count >= 1) sb.Append(UrlEncode("&"));
sb.Append(UrlEncode(urlItem.Key + "=" + urlItem.Value));
}
return sb.ToString();
}
private string GetOAuthAccessUrl(OAuthToken authToken, string signature, string random, string timestamp)
{
var urlDict = new SortedDictionary<string, string>
{
{ "oauth_consumer_key", CONSUMER_KEY},
{ "oauth_nonce", random},
{ "oauth_signature", signature },
{ "oauth_signature_method", UrlEncode(SIGNATURE_METHOD)},
{ "oauth_timestamp", timestamp},
{ "oauth_token", END_USER_AUTHORISATION_REQUEST_TOKEN },
{ "oauth_version", AUTH_VERSION}
};
StringBuilder sb = new StringBuilder();
sb.Append(BASE_URL_REQUEST_ACCESS_TOKEN + "?");
int count = 0;
foreach (var urlItem in urlDict)
{
count++;
if (count > 1) sb.Append("&");
sb.Append(urlItem.Key + "=" + urlItem.Value);
}
return sb.ToString();
}
private string ComputeHash(string data, string consumerSecret, string tokenSecret = null)
{
// Construct secret key based on consumer key (and optionally include token secret)
string secretKey = consumerSecret + "&";
if (tokenSecret != null) secretKey += tokenSecret;
// Initialise with secret key
System.Security.Cryptography.HMACSHA1 hmacsha = new System.Security.Cryptography.HMACSHA1(Encoding.ASCII.GetBytes(secretKey));
hmacsha.Initialize();
// Convert data into byte array
byte[] dataBuffer = Encoding.ASCII.GetBytes(data);
// Computer hash of data byte array
byte[] hashBytes = hmacsha.ComputeHash(dataBuffer);
// Return the base 64 of the result
return Convert.ToBase64String(hashBytes);
}
// Get random string
private string GetRandomString()
{
return Guid.NewGuid().ToString().Replace("-", "");
}
// Get timestamp
private string GetTimestamp()
{
var ts = DateTime.UtcNow - new DateTime(1970, 1, 1, 0, 0, 0, 0);
return Convert.ToInt64(ts.TotalSeconds).ToString();
}
// Url Encode (as Uri.Escape is reported to be not appropriate for this purpose)
protected string UnreservedChars = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789-_.~";
protected string UrlEncode(string value)
{
var result = new StringBuilder();
foreach (var symbol in value)
{
if (UnreservedChars.IndexOf(symbol) != -1)
result.Append(symbol);
else
result.Append('%' + $"{(int)symbol:X2}");
}
return result.ToString();
}
public async Task<string> GetData_BodyMeasures()
{
string rawdata = "";
try
{
string random = GetRandomString();
string timestamp = GetTimestamp();
string baseSignature = GetDataSignature_BodyMeasure(random, timestamp);
string hashSignature = ComputeHash(baseSignature, CONSUMER_SECRET, ACCESS_OAUTH_TOKEN_SECRET);
string codeSignature = UrlEncode(hashSignature);
string requestUrl = GetData_BodyMeasure_Url(codeSignature, random, timestamp);
HttpResponseMessage response = await client.GetAsync(requestUrl);
string responseBodyAsText = await response.Content.ReadAsStringAsync();
rawdata = responseBodyAsText;
}
catch (Exception ex)
{
}
return rawdata;
}
private string GetDataSignature_BodyMeasure(string random, string timestamp)
{
var urlDict = new SortedDictionary<string, string>
{
{ "oauth_consumer_key", CONSUMER_KEY},
{ "oauth_nonce", random},
{ "oauth_signature_method", SIGNATURE_METHOD},
{ "oauth_timestamp", timestamp},
{ "oauth_token", ACCESS_OAUTH_TOKEN },
{ "oauth_version", AUTH_VERSION},
{ "userid", USER_ID }
};
StringBuilder sb = new StringBuilder();
sb.Append("GET&" + UrlEncode(BASE_URL_REQUEST_BODY_MEASURE) + "&action%3Dgetmeas");
int count = 0;
foreach (var urlItem in urlDict)
{
count++;
if (count >= 1) sb.Append(UrlEncode("&"));
sb.Append(UrlEncode(urlItem.Key + "=" + urlItem.Value));
}
return sb.ToString();
}
private string GetData_BodyMeasure_Url(string signature, string random, string timestamp)
{
var urlDict = new SortedDictionary<string, string>
{
{ "action", "getmeas"},
{ "oauth_consumer_key", CONSUMER_KEY},
{ "oauth_nonce", random},
{ "oauth_signature", signature },
{ "oauth_signature_method", UrlEncode(SIGNATURE_METHOD)},
{ "oauth_timestamp", timestamp},
{ "oauth_token", ACCESS_OAUTH_TOKEN },
{ "oauth_version", AUTH_VERSION},
{ "userid", USER_ID }
};
StringBuilder sb = new StringBuilder();
sb.Append(BASE_URL_REQUEST_BODY_MEASURE + "?");
int count = 0;
foreach (var urlItem in urlDict)
{
count++;
if (count >= 1) sb.Append("&");
sb.Append(urlItem.Key + "=" + urlItem.Value);
}
return sb.ToString();
}