我想通過oauth(.net core C#)訪問我的Withings/Nokia縮放數據。Withings API - 無效簽名
說明書,可以發現: https://oauth.withings.com/en/api/oauthguide
和API指南這裏: https://developer.health.nokia.com/api#step1
我已經實現了第1部分 - 我得到一個身份驗證令牌和祕密。
部分 - 手動我已經檢索授權我withings我的應用程序的使用代碼擴展的數據 - 即授權碼的回調(通過API開發者網頁)的結果。我假設這隻需要一次授權我的應用程序的訪問永久。如果我重新授權應用程序,我已將此值硬編碼到我的代碼中並進行更新。
現在我被困在第3部分 - 獲得訪問令牌/祕密。 錯誤=無效的簽名
(使用上面的頁面我已經能夠檢索我的4年價值數據,所以我知道它應該工作)。
我的基本簽名是相同於上述API測試頁(除了隨機數,簽名和時間戳)。
我的網址是相同於上述API測試頁(除了隨機數和時間戳)。
對我來說這個神祕的原因是爲什麼它適用於第1部分而不是第3部分。 它是不好的代碼,或者只是請求令牌必須在請求發出之前對應用程序/用戶數據進行授權? 但是當然,我不必每次都重新授權給用戶?
我本來搞砸第1部分,給了一個無效的簽名錯誤 - 這顯然與簽名的問題 - 但在第三部分我已經重新檢查了簽名,這是件好事。
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";
...
Withings w = new Withings();
OAuthToken t = await w.GetOAuthToken();
string token = t.OAuth_Token;
string secret = t.OAuth_Token_Secret;
OAuthAccessToken at = await w.GetOAuthAccess(t);
string aToken = at.OAuth_Token;
string aTokenSecret = at.OAuth_Token_Secret;
...
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();
}
注:
- 我已下令我的參數
- 我有一個體面的進行urlencode(正確我wr翁)
- 我有一個HMAC-SHA1散列(指正錯誤)
- 在使用開放圖書館不感興趣 - 我想解決這個代碼,而無需第三方工具
下面是輔助方法我使用:
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 = "abcdefghijklmnopqrstuvwxyzABCDEFGHIJKLMNOPQRSTUVWXYZ-_.~";
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();
}
謝謝,丹。