Аутентификация REST API (OAuth 1.0) с использованием проблемы C # с добавлением параметров строки запроса - PullRequest
0 голосов
/ 16 февраля 2019

Я пытаюсь добавить параметры строки запроса в запрос API GET, который использует oauth 1.0.Мне удалось получить ответ в этом посте, чтобы он работал без параметров строки запроса: Проверка подлинности API REST (OAuth 1.0) с использованием C #

Проблема, с которой я столкнулся, заключается в том, что я пытаюсьдобавьте параметры строки запроса в запрос GET, не указав их в URL-адресе, поскольку это не соответствует и приведет к ошибке:

SIGNATURE_INVALID: Неверная подпись - сообщение - код BAD_OAUTH_REQUEST: 401

Пожалуйста, кто-нибудь может предложить несколько советов о том, как это сделать, поскольку я полностью застрял в том, где и как их следует добавлять.

    const string consumerKey = "REMOVED";
    const string consumerSecret = "REMOVED";
    const string tokenSecret = "REMOVED";
    const string tokenValue = "REMOVED";
    const string url = "https://api.bricklink.com/api/store/v1/orders";
    //FULL URL WITH QS PARAMS IS: https://api.bricklink.com/api/store/v1/orders?direction=in
    string Escape(string s)
    {
        // /714185/kak-zastavit-uri-escapedatastring-sootvetstvovat-rfc-3986
        var charsToEscape = new[] { "!", "*", "'", "(", ")" };
        var escaped = new StringBuilder(Uri.EscapeDataString(s));
        foreach (var t in charsToEscape)
        {
            escaped.Replace(t, Uri.HexEscape(t[0]));
        }
        return escaped.ToString();
    }

    protected void Button1_Click(object sender, EventArgs e)
    {
        var httpWebRequest = (HttpWebRequest)WebRequest.Create(url);
        httpWebRequest.Method = "GET";
        var timeStamp = ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
        var nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(timeStamp));

        var signatureBaseString = Escape(httpWebRequest.Method.ToUpper()) + "&";
        signatureBaseString += EscapeUriDataStringRfc3986(url.ToLower()) + "&";
        signatureBaseString += EscapeUriDataStringRfc3986(
            "oauth_consumer_key=" + EscapeUriDataStringRfc3986(consumerKey) + "&" +
            "oauth_nonce=" + EscapeUriDataStringRfc3986(nonce) + "&" +
            "oauth_signature_method=" + EscapeUriDataStringRfc3986("HMAC-SHA1") + "&" +
            "oauth_timestamp=" + EscapeUriDataStringRfc3986(timeStamp) + "&" +
            "oauth_token=" + EscapeUriDataStringRfc3986(tokenValue) + "&" +
            "oauth_version=" + EscapeUriDataStringRfc3986("1.0")

            //ATTEMPT AT ADDING QS PARAM
            //"direction=" + SimpleQuote("out")

            );

        lblResult.Text=(@"signatureBaseString: " + signatureBaseString+ "<br/><br/>");

        var key = EscapeUriDataStringRfc3986(consumerSecret) + "&" + EscapeUriDataStringRfc3986(tokenSecret);
        lblResult.Text+=(@"key: " + key);
        var signatureEncoding = new ASCIIEncoding();
        var keyBytes = signatureEncoding.GetBytes(key);
        var signatureBaseBytes = signatureEncoding.GetBytes(signatureBaseString);
        string signatureString;
        using (var hmacsha1 = new HMACSHA1(keyBytes))
        {
            var hashBytes = hmacsha1.ComputeHash(signatureBaseBytes);
            signatureString = Convert.ToBase64String(hashBytes);
        }
        signatureString = EscapeUriDataStringRfc3986(signatureString);
        lblResult.Text+=(@"signatureString: " + signatureString + "<br/><br/>");


        var header =
            "OAuth realm=" + SimpleQuote("") + "," +
            "oauth_consumer_key=" + SimpleQuote(consumerKey) + "," +
            "oauth_nonce=" + SimpleQuote(nonce) + "," +
            "oauth_signature_method=" + SimpleQuote("HMAC-SHA1") + "," +
            "oauth_timestamp=" + SimpleQuote(timeStamp) + "," +
            "oauth_token=" + SimpleQuote(tokenValue) + "," +
            "oauth_version=" + SimpleQuote("1.0") + "," +
            "oauth_signature= " + SimpleQuote(signatureString);
            //ATTEMPT MADE HERE TOO
        lblResult.Text+=(@"header: " + header + "<br/><br/>");
        httpWebRequest.Headers.Add(HttpRequestHeader.Authorization, header);

        var response = httpWebRequest.GetResponse();
        var characterSet = ((HttpWebResponse)response).CharacterSet;
        var responseEncoding = characterSet == ""
            ? Encoding.UTF8
            : Encoding.GetEncoding(characterSet ?? "utf-8");
        var responsestream = response.GetResponseStream();
        if (responsestream == null)
        {
            throw new ArgumentNullException(nameof(characterSet));
        }
        using (responsestream)
        {
            var reader = new StreamReader(responsestream, responseEncoding);
            var result = reader.ReadToEnd();
            lblResult.Text+=(@"result: " + result);
        }
    }

    string SimpleQuote(string s) => '"' + s + '"';

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

    /// <summary>
    /// Escapes a string according to the URI data string rules given in RFC 3986.
    /// </summary>
    /// <param name="value">The value to escape.</param>
    /// <returns>The escaped value.</returns>
    /// <remarks>
    /// The <see cref="Uri.EscapeDataString"/> method is <i>supposed</i> to take on
    /// RFC 3986 behavior if certain elements are present in a .config file.  Even if this
    /// actually worked (which in my experiments it <i>doesn't</i>), we can't rely on every
    /// host actually having this configuration element present.
    /// </remarks>
    internal static string EscapeUriDataStringRfc3986(string value)
    {
        // Start with RFC 2396 escaping by calling the .NET method to do the work.
        // This MAY sometimes exhibit RFC 3986 behavior (according to the documentation).
        // If it does, the escaping we do that follows it will be a no-op since the
        // characters we search for to replace can't possibly exist in the string.
        StringBuilder escaped = new StringBuilder(Uri.EscapeDataString(value));

        // Upgrade the escaping to RFC 3986, if necessary.
        for (int i = 0; i < UriRfc3986CharsToEscape.Length; i++)
        {
            escaped.Replace(UriRfc3986CharsToEscape[i], Uri.HexEscape(UriRfc3986CharsToEscape[i][0]));
        }

        // Return the fully-RFC3986-escaped string.
        return escaped.ToString();
    }
...