使用OAuth 1.0 API签名无效

时间:2016-05-19 11:22:04

标签: api oauth

我正在使用使用OAuth 1.0的API。除了使用标准方法之外,API的网站上没有文档。我在推特网站https://dev.twitter.com/oauth/overview/creating-signatures上关注了指南。

对我来说似乎一切都很好,但我不断收到一条消息,告诉我签名无效。我开始在github上找到一个类,我收到了签名错误。这个类非常复杂,所以我编写了自己的简单类(使用C#)。我有一个构造函数,可以正确设置此处使用的所有值。我100%确定没有丢失数据,问题必须与签名/请求的生成方式有关,但据我所知,一切都设置正确。输出标题看起来正确,并填充了所有内容。有什么想法是错的吗?

public string GenerateHeaderString(string url, string method)
{
    string auth = "OAuth oauth_consumer_key=\"" + ConsumerKey + "\",oauth_token=\"" + HttpUtility.UrlEncode(Token) + "\",oauth_signature_method=\"" + SignatureMethod
        + "\",oauth_timestamp=\"" + Timestamp + "\",oauth_nonce=\"" + Nonce + "\",oauth_version=\"" + Version + "\",oauth_signature=\"" + GenerateSignature(url, method) + "\"";
    return auth;            
}

public string GenerateSignature(string url, string method)
{
    string signature = method + "&" + HttpUtility.UrlEncode(url) + "&" + HttpUtility.UrlEncode("oauth_consumer_key=" + ConsumerKey
        + "&oauth_nonce=" + Nonce + "&oauth_signature_method=" + SignatureMethod + "&oauth_timestamp="
        + Timestamp + "&oauth_token=" + Token + "&oauth_version=" + Version);
    switch(SignatureMethod)
    {
        case "HMAC-SHA1": 
            string keystring = string.Format("{0}&{1}", HttpUtility.UrlEncode(this.ConsumerSecret),HttpUtility.UrlEncode(this.TokenSecret));

            var hmacsha1 = new HMACSHA1
            {
                Key = System.Text.Encoding.ASCII.GetBytes(keystring)
            };
            byte[] dataBuffer = System.Text.Encoding.ASCII.GetBytes(signature);
            byte[] hashBytes = hmacsha1.ComputeHash(dataBuffer);

            this.Signature = HttpUtility.UrlEncode(Convert.ToBase64String(hashBytes));
        break;
    }
    return this.Signature;
}

1 个答案:

答案 0 :(得分:0)

我认为问题是你需要在哈希之前对签名进行URLEncode编码。前两个&符号不会被编码,但其他一切都会编码。这是我使用的一些代码。我遇到的唯一问题是查询字符串在值中包含空格。

        var signatureType = string.Empty;

        switch (((OAuth1)webRequestDetails.Authentication).SignatureMethod)
        {
            case SignatureMethod.HMACSHA1:
            {
                signatureType = "HMAC-SHA1";
                break;
                }
            case SignatureMethod.HMACSHA256:
                {
                    signatureType = "HMAC-SHA256";
                    break;
                }
            case SignatureMethod.PLAINTEXT:
                {
                    signatureType = "PLAINTEXT";
                    break;
                }
        }

        var baseUrl = webRequestDetails.Url;
        var queryStrings = new List<string>();

        var queryStartIndex = baseUrl.IndexOf("?", StringComparison.Ordinal);
        if (queryStartIndex != -1)
        {
            queryStrings = baseUrl.Substring(queryStartIndex + 1, baseUrl.Length - queryStartIndex - 1).Split('&').ToList();
            baseUrl = baseUrl.Substring(0, queryStartIndex);
        }

        //string builder will be used to append all the key value pairs
        var stringBuilder = new StringBuilder();
        stringBuilder.Append(httpMethod.Method.ToUpper() + "&");
        stringBuilder.Append(Uri.EscapeDataString(baseUrl));
        stringBuilder.Append("&");

        //the key value pairs have to be sorted by encoded key
        var dictionary = new SortedDictionary<string, string>
        {
            {"oauth_version", "1.0"},
            {"oauth_consumer_key", ((OAuth1) webRequestDetails.Authentication).ConsumerKey},
            {"oauth_nonce", ((OAuth1) webRequestDetails.Authentication).Nonce},
            {"oauth_signature_method", signatureType},
            {"oauth_timestamp", ((OAuth1) webRequestDetails.Authentication).TimeStamp},
            {"oauth_token", ((OAuth1) webRequestDetails.Authentication).Token}
        };

        //merge in the querystrings
        foreach (var queryString in queryStrings)
        {
            var queryStringParts = queryString.Split('=');
            dictionary.Add(queryStringParts[0], queryStringParts[1]);
        }

        foreach (var keyValuePair in dictionary)
        {
            //append a = between the key and the value and a & after the value
            stringBuilder.Append(Uri.EscapeDataString($"{keyValuePair.Key}={keyValuePair.Value}&"));
        }

        var signatureBaseString = stringBuilder.ToString().Substring(0, stringBuilder.Length - 3);

        //generation the signature key the hash will use
        var signatureKey =
            Uri.EscapeDataString(((OAuth1) webRequestDetails.Authentication).ConsumerSecret) + "&" +
            Uri.EscapeDataString(((OAuth1) webRequestDetails.Authentication).TokenSecret);

        var hmacsha1 = new HMACSHA1(
            new ASCIIEncoding().GetBytes(signatureKey));

        //hash the values
        var signatureString = Convert.ToBase64String(
            hmacsha1.ComputeHash(
                new ASCIIEncoding().GetBytes(signatureBaseString)));

        return signatureString;