带有普通查询字符串的 HttpClient GET 请求(连同 oAuth1.0)

Posted

技术标签:

【中文标题】带有普通查询字符串的 HttpClient GET 请求(连同 oAuth1.0)【英文标题】:HttpClient GET request with plain querystring (together with oAuth1.0) 【发布时间】:2021-12-07 09:09:12 【问题描述】:

我正在尝试做一个简单的请求,但我无法让它工作。 我认为这与单个参数有关。

示例代码:

var uri = new Uri("http://www.mydomain.nl/?eq(id,8c17b598-67e4-4b9b-8d18-ab0918ed82d9)");
var consumerKey = "[mykey]";
var consumerSecret = "[mysecret]";
var token = OAuthRequest.ForRequestToken(consumerKey, consumerSecret);
token.RequestUrl = $"uri.Scheme://uri.Hosturi.AbsolutePath";
var arguments = HttpUtility.ParseQueryString(uri.Query);
var header = token.GetAuthorizationHeader(arguments);
using (var httpClient = new HttpClient())

    var request = new HttpRequestMessage();
    request.RequestUri = uri;
    request.Headers.Add("Authorization", header);
    using (var response = await httpClient.SendAsync(request))
    
        var data = await response.Content.ReadAsStringAsync();
        var x = 1;
    

我确实需要 oAuth1 的授权码,当我尝试在没有 eq(id,8c17b598-67e4-4b9b-8d18-ab0918ed82d9) 的情况下执行此操作时它可以工作,但添加它时它会停止工作。现在不确定这是否与 oAuth1 或是否与常规请求有关。

但我确实记得过去使用非键值查询参数存在一些问题。你们有什么想法吗?

【问题讨论】:

【参考方案1】:

我注意到这是由我使用的 oAuth1 实现引起的。我查看了几个示例,例如 twitter,并创建了我自己的版本,并将结果与​​ Postman 生成的结果进行了比较,而 twitter 在他们的示例中显示: https://developer.twitter.com/en/docs/authentication/oauth-1-0a/creating-a-signature#f2

我现在使用的代码:

/// <summary>
/// OAuth 1.0 signing
/// </summary>
public class OAuth1

    #region CONSTRUCTORS

    /// <summary>
    /// Default constructor
    /// </summary>
    public OAuth1()
    
        this.Timestamp  = ((int)(DateTime.UtcNow - new DateTime(1970, 1, 1)).TotalSeconds).ToString();
        this.Nonce = Convert.ToBase64String(Encoding.UTF8.GetBytes(this.Timestamp + this.Timestamp + this.Timestamp));
        this.SignatureMethod = "HMAC-SHA1";
        this.Version = "1.0";
        this.Data = new Dictionary<string, string>();
    

    #endregion
    #region METHODS_PUBLIC

    /// <summary>
    /// Get authorization header
    /// </summary>
    /// <returns></returns>
    public string GetAuthorizationHeader()
    
        var properties = this.GetOAuthProperties();
        properties.Add("oauth_signature", Uri.EscapeDataString(this.GetSignature()));
        return "OAuth " + string.Join(",", properties.Select(q => $"q.Key=\"q.Value\""));
    

    /// <summary>
    /// Get signature only
    /// </summary>
    /// <returns></returns>
    public string GetSignature()
    
        var uriBuilder = new UriBuilder(this.RequestUri);
        uriBuilder.Query = "";
        var signValues = new List<string>();
        signValues.Add(this.RequestMethod.ToString().ToUpperInvariant());
        signValues.Add(uriBuilder.Uri.AbsoluteUri);
        signValues.Add(string.Join("&", this.GetSigningProperties().Select(q => $"q.Key=q.Value")));
        var signKey = $"this.ConsumerSecret&this.TokenSecret";
        var signMessage = string.Join("&", signValues.Select(q => Uri.EscapeDataString(q)));
        return this.GetSha1Hash(signKey, signMessage);
    

    #endregion
    #region METHODS_PRIVATE

    /// <summary>
    /// Get properties which should be part of the signing process
    /// </summary>
    /// <returns></returns>
    private SortedDictionary<string,string> GetSigningProperties()
    
        var result = this.GetOAuthProperties();
        var arguments = HttpUtility.ParseQueryString(this.RequestUri.Query);
        for (var i = 0; i < arguments.Count; i++)
        
            var key = arguments.Keys[i];
            var value = arguments.GetValues(i)[0];
            if (string.IsNullOrEmpty(key))
            
                key = value;
                value = null;
            
            result.Add(Uri.EscapeDataString(key ?? ""), Uri.EscapeDataString(value ?? ""));
        
        foreach(var dataArg in this.Data)
        
            result.Add(Uri.EscapeDataString(dataArg.Key), Uri.EscapeDataString(dataArg.Value));
        
        return result;
    

    /// <summary>
    /// Get SHA1 Hash
    /// </summary>
    /// <param name="key"></param>
    /// <param name="message"></param>
    /// <returns></returns>
    private string GetSha1Hash(string key, string message)
    
        var encoding = new ASCIIEncoding();
        byte[] keyBytes = encoding.GetBytes(key);
        byte[] messageBytes = encoding.GetBytes(message);
        string strSignature = string.Empty;
        using (var SHA1 = new HMACSHA1(keyBytes))
        
            var Hashed = SHA1.ComputeHash(messageBytes);
            strSignature = Convert.ToBase64String(Hashed);
        
        return strSignature;
    

    /// <summary>
    /// Get OAuth properties only (used for signing and header)
    /// </summary>
    /// <returns></returns>
    private SortedDictionary<string, string> GetOAuthProperties()
    
        var result = new SortedDictionary<string, string>();
        result.Add(Uri.EscapeDataString("oauth_consumer_key"), Uri.EscapeDataString(this.ConsumerKey));
        result.Add(Uri.EscapeDataString("oauth_nonce"), Uri.EscapeDataString(this.Nonce));
        result.Add(Uri.EscapeDataString("oauth_signature_method"), Uri.EscapeDataString(this.SignatureMethod));
        result.Add(Uri.EscapeDataString("oauth_timestamp"), Uri.EscapeDataString(this.Timestamp));
        if (!string.IsNullOrEmpty(this.Token))
        
            result.Add(Uri.EscapeDataString("oauth_token"), Uri.EscapeDataString(this.Token));
        
        result.Add(Uri.EscapeDataString("oauth_version"), Uri.EscapeDataString(this.Version));
        return result;
    

    #endregion
    #region PROPERTIES

    /// <summary>
    /// Request method
    /// </summary>
    public Models.Thpr.Common.Enums.ERequestMethod RequestMethod  get; set; 

    /// <summary>
    /// Request URI
    /// </summary>
    public Uri RequestUri  get; set; 

    /// <summary>
    /// Timestamp
    /// </summary>
    public string Timestamp  get; set; 

    /// <summary>
    /// Nonce
    /// </summary>
    public string Nonce  get; set;  

    /// <summary>
    /// Consumer key
    /// </summary>
    public string ConsumerKey  get; set; 

    /// <summary>
    /// Consumer secret
    /// </summary>
    public string ConsumerSecret  get; set; 

    /// <summary>
    /// Signature Method
    /// </summary>
    public string SignatureMethod  get; set; 

    /// <summary>
    /// Token
    /// </summary>
    public string Token  get; set; 

    /// <summary>
    /// Token secret
    /// </summary>
    public string TokenSecret  get; set; 

    /// <summary>
    /// Version
    /// </summary>
    public string Version  get; set; 

    /// <summary>
    /// Data arguments
    /// </summary>
    public Dictionary<string, string> Data  get; set; 

    #endregion

【讨论】:

以上是关于带有普通查询字符串的 HttpClient GET 请求(连同 oAuth1.0)的主要内容,如果未能解决你的问题,请参考以下文章

HttpClient使用详解与实战一:普通的GET和POST请求

带有 .Get() 对 Azure 搜索 API 的请求的 Angular HttpClient“未知错误”

带有“@”的 HttpClient 访问 url(在符号处)

带有查询字符串参数的node.js http'get'请求

带有 XMLParser 的 AFNetworking HTTPClient 子类

如何使用HttpClient模拟浏览器GET POST