Interactive Brokers – я продолжаю получать сообщение о недействительном потребителе при запросе токена OAuthC#

Место общения программистов C#
Ответить
Anonymous
 Interactive Brokers – я продолжаю получать сообщение о недействительном потребителе при запросе токена OAuth

Сообщение Anonymous »

У меня есть действительный потребительский ключ, и я не могу заставить работать OAuth Interactive Brokers Web API.

{"error":"id: 3931, ошибка: недопустимый потребитель","statusCode":401
Я что-то упустил в своей реализации?
Это тоже на GitHub.
var httpClient = new HttpClient
{
BaseAddress = new Uri("https://www.interactivebrokers.com/tradingapi/v1/")
};

var restClient = new IBRestClient(httpClient);
var response = await restClient.RequestTokenAsync("xxxxx");

Console.WriteLine($"Response: {response}");

Console.ReadLine();

public sealed class IBRestClient
{
private readonly HttpClient _httpClient;

public IBRestClient(HttpClient httpClient)
{
_httpClient = httpClient;
}

public async ValueTask RequestTokenAsync(string consumerKey)
{
const string requestUri = "oauth/request_token";

var request = new HttpRequestMessage(HttpMethod.Post, requestUri);

var baseUrl = _httpClient.BaseAddress!.AbsoluteUri;
var authorizationHeader = OAuthHelper.GetAuthorizationHeader($"{baseUrl}{requestUri}", "POST", consumerKey);

var authSplit = authorizationHeader.Split(' ');
request.Headers.Authorization = new AuthenticationHeaderValue(authSplit[0], authSplit[1]);

var response = await _httpClient.SendAsync(request);
return await response.Content.ReadAsStringAsync();
}
}

public static class OAuthHelper
{
private static readonly RandomNumberGenerator Random = RandomNumberGenerator.Create();

public static string GetAuthorizationHeader(string uri, string method, string consumerKey)
{
var oauthParameters = new Dictionary
{
{ "oauth_consumer_key", consumerKey },
{ "oauth_signature_method", "RSA-SHA256" },
{ "oauth_timestamp", GetTimestamp() },
{ "oauth_nonce", GetNonce() },
{ "oauth_callback", "oob" }
};

// The request parameters are collected, sorted and concatenated into a normalized string
var queryParameters = ExtractQueryParams(uri);
var oauthParamString = GetOAuthParamString(queryParameters, oauthParameters);
var baseUri = GetBaseUriString(uri);

// Signature Base String
var signatureBaseString = GetSignatureBaseString(baseUri, method, oauthParamString);

var pem = File.ReadAllText("private_encryption.pem");
var signingKey = RSA.Create();
signingKey.ImportFromPem(pem);

var signature = SignSignatureBaseString(signatureBaseString, Encoding.UTF8, signingKey);
oauthParameters.Add("oauth_signature", signature);

// Constructs and returns the Authorization header
var sb = new StringBuilder();
foreach (var param in oauthParameters)
{
sb
.Append(sb.Length == 0 ? "OAuth " : ",")
.Append(param.Key)
.Append("=\"")
.Append(ToUriRfc3986(param.Value))
.Append('"');
}

return sb.ToString();
}

///
/// Parse query parameters out of the URL.
///
private static Dictionary ExtractQueryParams(string uri)
{
var queryParamCollection = new Dictionary();
var beginIndex = uri.IndexOf('?');
if (beginIndex 0 ? "&" : string.Empty)
.Append(parameter.Key)
.Append('=')
.Append(value);
}
}

return parameterString.ToString();
}

///
/// Normalizes the URL.
///
private static string GetBaseUriString(string uriString)
{
var uri = new Uri(uriString);
var lowerCaseScheme = uri.Scheme.ToLower();
var lowerCaseAuthority = uri.Authority.ToLower();
var path = uri.AbsolutePath;

if (("http".Equals(lowerCaseScheme) && uri.Port == 80) || ("https".Equals(lowerCaseScheme) && uri.Port == 443))
{
// Remove port if it matches the default for scheme
var index = lowerCaseAuthority.LastIndexOf(':');
if (index >= 0)
{
lowerCaseAuthority = lowerCaseAuthority[..index];
}
}

if (string.IsNullOrEmpty(path))
{
path = "/";
}

return $"{lowerCaseScheme}://{lowerCaseAuthority}{path}"; // Remove query and fragment
}

///
/// The Signature Base String is a consistent reproducible concatenation of the request elements into a single string.
///
private static string GetSignatureBaseString(string baseUri, string httpMethod, string oauthParamString)
{
return httpMethod.ToUpper() // Uppercase HTTP method
+ "&" + ToUriRfc3986(baseUri) // Base URI
+ "&" + ToUriRfc3986(oauthParamString); // OAuth parameter string
}

///
/// Signs the signature base string using an RSA private key.
///
private static string SignSignatureBaseString(string baseString, Encoding encoding, RSA privateKey)
{
var hash = Sha256Digest(baseString, encoding);
var signedHashValue = privateKey.SignHash(hash, HashAlgorithmName.SHA256, RSASignaturePadding.Pkcs1);
return Convert.ToBase64String(signedHashValue);
}

///
/// Percent encodes entities.
///
private static string ToUriRfc3986(string input)
{
if (string.IsNullOrEmpty(input))
{
return input;
}

var escaped = new StringBuilder(Uri.EscapeDataString(input));
string[] uriRfc3986EscapedChars = { "!", "*", "'", "(", ")" };
foreach (var escapedChar in uriRfc3986EscapedChars)
{
escaped.Replace(escapedChar, UriHelper.HexEscape(escapedChar[0]));
}

return escaped.ToString();
}

///
/// Returns a cryptographic hash of the given input.
///
private static byte[] Sha256Digest(string input, Encoding encoding)
{
var inputBytes = encoding.GetBytes(input);
return SHA256.HashData(inputBytes);
}

///
/// Generates a 16 char random string for replay protection.
///
private static string GetNonce()
{
var data = new byte[8];
Random.GetBytes(data);
return BitConverter.ToString(data).Replace("-", string.Empty).ToLower();
}

///
/// Returns UNIX Timestamp.
///
private static string GetTimestamp()
{
return DateTimeOffset.UtcNow.ToUnixTimeSeconds().ToString();
}
}

internal static class UriHelper
{
private static readonly char[] HexUpperChars =
{
'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'A', 'B', 'C', 'D', 'E', 'F'
};

internal static string HexEscape(char character)
{
if (character > '\xff')
{
throw new ArgumentOutOfRangeException(nameof(character));
}

var chars = new char[3];
var pos = 0;
EscapeAsciiChar(character, chars, ref pos);
return new string(chars);
}

private static void EscapeAsciiChar(char ch, char[] to, ref int pos)
{
to[pos++] = '%';
to[pos++] = HexUpperChars[(ch & 0xf0) >> 4];
to[pos++] = HexUpperChars[ch & 0xf];
}
}


Подробнее здесь: https://stackoverflow.com/questions/750 ... -oauth-tok
Ответить

Быстрый ответ

Изменение регистра текста: 
Смайлики
:) :( :oops: :roll: :wink: :muza: :clever: :sorry: :angel: :read: *x)
Ещё смайлики…
   
К этому ответу прикреплено по крайней мере одно вложение.

Если вы не хотите добавлять вложения, оставьте поля пустыми.

Максимально разрешённый размер вложения: 15 МБ.

Вернуться в «C#»