如何使用 C# (dotnet core 3.1) 进行 OAuth 1 Twitter API 调用
How to make an OAuth 1 Twitter API call with C# (dotnet core 3.1)
我希望能够从 dotnet 核心 API 服务中搜索 Twitter 句柄。我查看了 users/search.json 的 Twitter 文档,并请求、借用和窃取了我可以从 Whosebug 等(见下文)中获得的代码示例,但我得到的只是:
{"errors":[{"code":215,"message":"Bad Authentication data."
}]}
当我执行生成的 curl 命令时。
很抱歉代码有点乱,但是有人能看出我做错了什么吗?或者更好的是,如果有一个图书馆可以为我做这件事,我一直找不到,那就更好了。
using Xunit;
using System;
using System.Linq;
using System.Collections.Generic;
using OAuth; // OAuth.DotNetCore, 3.0.1
using System.IO;
using System.Net;
namespace TwitterLibTest
{
public class BuildHeaderTest
{
private static readonly string consumerKey = "...";
private static readonly string consumerSecret = "...";
private static readonly string method = "GET";
private static readonly OAuthSignatureMethod oauthSignatureMethod = OAuthSignatureMethod.HmacSha1;
private static readonly string oauthVersion = "1.0a";
[Fact]
public void Header()
{
var url = "https://api.twitter.com/1.1/users/search.json";
var generatedNonce = RandomString(32);
var generatedTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
var oauthToken = BuildAuthToken(consumerKey, consumerSecret);
var generatedSignature = GetSignatureBaseString(method, url, generatedTimestamp, generatedNonce, consumerKey, oauthToken, oauthSignatureMethod.ToString(), oauthVersion, new SortedDictionary<string, string>());
Console.WriteLine($"curl --request GET --url '{url}?q=soccer' --header 'authorization: OAuth oauth_consumer_key=\"{consumerKey}\", oauth_nonce=\"{generatedNonce}\", oauth_signature=\"{generatedSignature}\", oauth_signature_method=\"{oauthSignatureMethod.ToString()}\", oauth_timestamp=\"{generatedTimestamp}\", oauth_token=\"{oauthToken}\", oauth_version=\"{oauthVersion}\"'");
}
private static Random random = new Random();
private static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
//
private static string GetSignatureBaseString(string method, string strUrl, string timeStamp,
string nonce, string strConsumer, string strOauthToken, string oauthSignatureMethod,
string oauthVersion, SortedDictionary<string, string> data)
{
//1.Convert the HTTP Method to uppercase and set the output string equal to this value.
string Signature_Base_String = method.ToUpper();
Signature_Base_String = Signature_Base_String.ToUpper();
//2.Append the ‘&’ character to the output string.
Signature_Base_String = Signature_Base_String + "&";
//3.Percent encode the URL and append it to the output string.
string PercentEncodedURL = Uri.EscapeDataString(strUrl);
Signature_Base_String = Signature_Base_String + PercentEncodedURL;
//4.Append the ‘&’ character to the output string.
Signature_Base_String = Signature_Base_String + "&";
//5.append OAuth parameter string to the output string.
var parameters = new SortedDictionary<string, string>
{
{"oauth_consumer_key", strConsumer},
{"oauth_token", strOauthToken },
{"oauth_signature_method", oauthSignatureMethod},
{"oauth_timestamp", timeStamp},
{"oauth_nonce", nonce},
{"oauth_version", oauthVersion}
};
//6.append parameter string to the output string.
foreach (KeyValuePair<string, string> elt in data)
{
parameters.Add(elt.Key, elt.Value);
}
bool first = true;
foreach (KeyValuePair<string, string> elt in parameters)
{
if (first)
{
Signature_Base_String = Signature_Base_String + Uri.EscapeDataString(elt.Key + "=" + elt.Value);
first = false;
}
else
{
Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&" + elt.Key + "=" + elt.Value);
}
}
return Signature_Base_String;
}
private string BuildAuthToken(string consumerKey, string consumerSecret)
{
var client = Client(consumerKey, consumerSecret);
var response = Get(client);
var tokenMap = Parse(response);
return tokenMap["oauth_token"];
}
private static OAuthRequest Client(string consumerKey, string consumerSecret)
{
return new OAuthRequest
{
Method = method,
Type = OAuthRequestType.RequestToken,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ConsumerKey = consumerKey,
ConsumerSecret = consumerSecret,
RequestUrl = "https://api.twitter.com/oauth/request_token",
Version = oauthVersion,
};
}
private static HttpWebResponse Get(OAuthRequest client)
{
string auth = client.GetAuthorizationHeader();
var request = (HttpWebRequest) WebRequest.Create(client.RequestUrl);
request.Headers.Add("Authorization", auth);
return (HttpWebResponse) request.GetResponse();
}
private static Dictionary<string, string> Parse(HttpWebResponse response)
{
using var stream = response.GetResponseStream() ;
using var reader = new StreamReader( stream );
var responseAsText = reader.ReadToEnd();
var map = new Dictionary<string, string>();
foreach( var token in responseAsText.Split("&"))
{
var tokens = token.Split("=");
map.Add(tokens[0], tokens[1]);
}
return map;
}
}
}
我认为您不需要像那样分别完成所有签名和签名工作 - 这是一个 example project,它也使用 OAuth.DotNetCore, "do it for you"。在这种情况下,我直接使用了 HttpWebRequest,而不是使用 curl 命令。
using System;
using OAuth;
using System.Net;
using System.IO;
namespace TwitterDotNetCore
{
class Program
{
static void Main(string[] args)
{
// convenient to load keys and tokens from a config file for testing
// edit .env to add your keys and tokens (no quotation marks)
DotNetEnv.Env.Load();
string CONSUMER_KEY = System.Environment.GetEnvironmentVariable("CONSUMER_KEY");
string CONSUMER_TOKEN = System.Environment.GetEnvironmentVariable("CONSUMER_TOKEN");
string ACCESS_TOKEN = System.Environment.GetEnvironmentVariable("ACCESS_TOKEN");
string ACCESS_TOKEN_SECRET = System.Environment.GetEnvironmentVariable("ACCESS_TOKEN_SECRET");
// this is the endpoint we will be calling
string REQUEST_URL = "https://api.twitter.com/1.1/users/search.json?q=soccer";
// Create a new connection to the OAuth server, with a helper method
OAuthRequest client = OAuthRequest.ForProtectedResource("GET", CONSUMER_KEY, CONSUMER_TOKEN, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);
client.RequestUrl = REQUEST_URL;
// add HTTP header authorization
string auth = client.GetAuthorizationHeader();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(client.RequestUrl);
request.Headers.Add("Authorization", auth);
Console.WriteLine("Calling " + REQUEST_URL);
// make the call and print the string value of the response JSON
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string strResponse = reader.ReadToEnd();
Console.WriteLine(strResponse); // we have a string (JSON)
}
}
}
结果我只需要 https://github.com/linvi/tweetinvi 和:
Auth.SetUserCredentials(APIkey, APISecretKey, AccessToken, AccessTokenSecret);
Search.SearchUsers("...").Select(u => ...);
我希望能够从 dotnet 核心 API 服务中搜索 Twitter 句柄。我查看了 users/search.json 的 Twitter 文档,并请求、借用和窃取了我可以从 Whosebug 等(见下文)中获得的代码示例,但我得到的只是:
{"errors":[{"code":215,"message":"Bad Authentication data."
}]}
当我执行生成的 curl 命令时。
很抱歉代码有点乱,但是有人能看出我做错了什么吗?或者更好的是,如果有一个图书馆可以为我做这件事,我一直找不到,那就更好了。
using Xunit;
using System;
using System.Linq;
using System.Collections.Generic;
using OAuth; // OAuth.DotNetCore, 3.0.1
using System.IO;
using System.Net;
namespace TwitterLibTest
{
public class BuildHeaderTest
{
private static readonly string consumerKey = "...";
private static readonly string consumerSecret = "...";
private static readonly string method = "GET";
private static readonly OAuthSignatureMethod oauthSignatureMethod = OAuthSignatureMethod.HmacSha1;
private static readonly string oauthVersion = "1.0a";
[Fact]
public void Header()
{
var url = "https://api.twitter.com/1.1/users/search.json";
var generatedNonce = RandomString(32);
var generatedTimestamp = DateTimeOffset.Now.ToUnixTimeSeconds().ToString();
var oauthToken = BuildAuthToken(consumerKey, consumerSecret);
var generatedSignature = GetSignatureBaseString(method, url, generatedTimestamp, generatedNonce, consumerKey, oauthToken, oauthSignatureMethod.ToString(), oauthVersion, new SortedDictionary<string, string>());
Console.WriteLine($"curl --request GET --url '{url}?q=soccer' --header 'authorization: OAuth oauth_consumer_key=\"{consumerKey}\", oauth_nonce=\"{generatedNonce}\", oauth_signature=\"{generatedSignature}\", oauth_signature_method=\"{oauthSignatureMethod.ToString()}\", oauth_timestamp=\"{generatedTimestamp}\", oauth_token=\"{oauthToken}\", oauth_version=\"{oauthVersion}\"'");
}
private static Random random = new Random();
private static string RandomString(int length)
{
const string chars = "ABCDEFGHIJKLMNOPQRSTUVWXYZ0123456789";
return new string(Enumerable.Repeat(chars, length)
.Select(s => s[random.Next(s.Length)]).ToArray());
}
//
private static string GetSignatureBaseString(string method, string strUrl, string timeStamp,
string nonce, string strConsumer, string strOauthToken, string oauthSignatureMethod,
string oauthVersion, SortedDictionary<string, string> data)
{
//1.Convert the HTTP Method to uppercase and set the output string equal to this value.
string Signature_Base_String = method.ToUpper();
Signature_Base_String = Signature_Base_String.ToUpper();
//2.Append the ‘&’ character to the output string.
Signature_Base_String = Signature_Base_String + "&";
//3.Percent encode the URL and append it to the output string.
string PercentEncodedURL = Uri.EscapeDataString(strUrl);
Signature_Base_String = Signature_Base_String + PercentEncodedURL;
//4.Append the ‘&’ character to the output string.
Signature_Base_String = Signature_Base_String + "&";
//5.append OAuth parameter string to the output string.
var parameters = new SortedDictionary<string, string>
{
{"oauth_consumer_key", strConsumer},
{"oauth_token", strOauthToken },
{"oauth_signature_method", oauthSignatureMethod},
{"oauth_timestamp", timeStamp},
{"oauth_nonce", nonce},
{"oauth_version", oauthVersion}
};
//6.append parameter string to the output string.
foreach (KeyValuePair<string, string> elt in data)
{
parameters.Add(elt.Key, elt.Value);
}
bool first = true;
foreach (KeyValuePair<string, string> elt in parameters)
{
if (first)
{
Signature_Base_String = Signature_Base_String + Uri.EscapeDataString(elt.Key + "=" + elt.Value);
first = false;
}
else
{
Signature_Base_String = Signature_Base_String + Uri.EscapeDataString("&" + elt.Key + "=" + elt.Value);
}
}
return Signature_Base_String;
}
private string BuildAuthToken(string consumerKey, string consumerSecret)
{
var client = Client(consumerKey, consumerSecret);
var response = Get(client);
var tokenMap = Parse(response);
return tokenMap["oauth_token"];
}
private static OAuthRequest Client(string consumerKey, string consumerSecret)
{
return new OAuthRequest
{
Method = method,
Type = OAuthRequestType.RequestToken,
SignatureMethod = OAuthSignatureMethod.HmacSha1,
ConsumerKey = consumerKey,
ConsumerSecret = consumerSecret,
RequestUrl = "https://api.twitter.com/oauth/request_token",
Version = oauthVersion,
};
}
private static HttpWebResponse Get(OAuthRequest client)
{
string auth = client.GetAuthorizationHeader();
var request = (HttpWebRequest) WebRequest.Create(client.RequestUrl);
request.Headers.Add("Authorization", auth);
return (HttpWebResponse) request.GetResponse();
}
private static Dictionary<string, string> Parse(HttpWebResponse response)
{
using var stream = response.GetResponseStream() ;
using var reader = new StreamReader( stream );
var responseAsText = reader.ReadToEnd();
var map = new Dictionary<string, string>();
foreach( var token in responseAsText.Split("&"))
{
var tokens = token.Split("=");
map.Add(tokens[0], tokens[1]);
}
return map;
}
}
}
我认为您不需要像那样分别完成所有签名和签名工作 - 这是一个 example project,它也使用 OAuth.DotNetCore, "do it for you"。在这种情况下,我直接使用了 HttpWebRequest,而不是使用 curl 命令。
using System;
using OAuth;
using System.Net;
using System.IO;
namespace TwitterDotNetCore
{
class Program
{
static void Main(string[] args)
{
// convenient to load keys and tokens from a config file for testing
// edit .env to add your keys and tokens (no quotation marks)
DotNetEnv.Env.Load();
string CONSUMER_KEY = System.Environment.GetEnvironmentVariable("CONSUMER_KEY");
string CONSUMER_TOKEN = System.Environment.GetEnvironmentVariable("CONSUMER_TOKEN");
string ACCESS_TOKEN = System.Environment.GetEnvironmentVariable("ACCESS_TOKEN");
string ACCESS_TOKEN_SECRET = System.Environment.GetEnvironmentVariable("ACCESS_TOKEN_SECRET");
// this is the endpoint we will be calling
string REQUEST_URL = "https://api.twitter.com/1.1/users/search.json?q=soccer";
// Create a new connection to the OAuth server, with a helper method
OAuthRequest client = OAuthRequest.ForProtectedResource("GET", CONSUMER_KEY, CONSUMER_TOKEN, ACCESS_TOKEN, ACCESS_TOKEN_SECRET);
client.RequestUrl = REQUEST_URL;
// add HTTP header authorization
string auth = client.GetAuthorizationHeader();
HttpWebRequest request = (HttpWebRequest)WebRequest.Create(client.RequestUrl);
request.Headers.Add("Authorization", auth);
Console.WriteLine("Calling " + REQUEST_URL);
// make the call and print the string value of the response JSON
HttpWebResponse response = (HttpWebResponse)request.GetResponse();
Stream dataStream = response.GetResponseStream();
StreamReader reader = new StreamReader(dataStream);
string strResponse = reader.ReadToEnd();
Console.WriteLine(strResponse); // we have a string (JSON)
}
}
}
结果我只需要 https://github.com/linvi/tweetinvi 和:
Auth.SetUserCredentials(APIkey, APISecretKey, AccessToken, AccessTokenSecret);
Search.SearchUsers("...").Select(u => ...);