Skip to content

Instantly share code, notes, and snippets.

@tmyt
Forked from anonymous/gist:3325279
Created August 11, 2012 15:48
Show Gist options
  • Save tmyt/3325351 to your computer and use it in GitHub Desktop.
Save tmyt/3325351 to your computer and use it in GitHub Desktop.
async/awaitでOAuthしてみるあれ
using System;
using System.Collections.Generic;
using System.IO;
using System.Linq;
using System.Net;
using System.Net.Http;
using System.Text;
using System.Text.RegularExpressions;
using System.Threading.Tasks;
using MFToolkit.Cryptography;
namespace Anemone.Shared
{
public enum RequestMethod
{
Get,
Post
}
public class OAuthClient
{
// ConsumerKey
public string ConsumerKey { get; set; }
public string ConsumerSecret { get; set; }
// AccessToken
public string AccessToken { get; set; }
public string AccessTokenSecret { get; set; }
// RequestParameter
public string Url { get; set; }
public Dictionary<string, string> Params { get; set; }
public RequestMethod Method { get; set; }
#region SHA1 Utils
private byte[] Sha1Sum(byte[] key)
{
return SHA1.Compute(key, 0, key.Length);
}
#endregion
#region HMACSHA1 Utils
private byte[] HmacSha1(byte[] buffer, byte[] key)
{
byte[] ohash = new byte[64];
byte[] ihash = new byte[64];
if (key.Length > 64) key = Sha1Sum(key);
key.CopyTo(ohash, 0);
key.CopyTo(ihash, 0);
for (int i = 0; i < 64; ++i) { ihash[i] ^= 0x36; ohash[i] ^= 0x5c; }
byte[] m = new byte[64 + buffer.Length];
ihash.CopyTo(m, 0);
buffer.CopyTo(m, 64);
var K = Sha1Sum(m);
m = new byte[64 + 20];
ohash.CopyTo(m, 0);
K.CopyTo(m, 64);
return Sha1Sum(m);
}
private byte[] HmacSha1(string buffer, string key)
{
var b = Encoding.UTF8.GetBytes(buffer);
var k = Encoding.UTF8.GetBytes(key);
return HmacSha1(b, k);
}
#endregion
#region Private Functions
const long EPOCH = 621355968000000000;
long UnixTime()
{
return (DateTime.Now.ToUniversalTime().Ticks - EPOCH) / 10000000;
}
string UrlEncode(string s)
{
Regex re = new Regex("%[0-9a-f]{2}");
string encoded = WebUtility.UrlEncode(s);
MatchCollection mc = re.Matches(encoded);
foreach (Match m in mc)
{
encoded = encoded.Replace(m.Value, m.Value.ToUpper());
}
return encoded.Replace("+", "%20");
}
string GetSHA1Hash(string s)
{
if (s == null) return "";
StringBuilder sb = new StringBuilder();
var hash = Sha1Sum(Encoding.UTF8.GetBytes(s));
foreach (byte c in hash)
{
sb.Append(c.ToString("X").PadLeft(2, '0'));
}
return sb.ToString();
}
string CreateNonce()
{
StringBuilder sb = new StringBuilder();
sb.Append(GetSHA1Hash(DateTime.Now.ToString() + DateTime.Now.ToString()));
sb.Append(GetSHA1Hash(AccessTokenSecret));
return sb.ToString();
}
string CreateAuthorizeHeader(string Url, string Method, Dictionary<string, string> Params)
{
List<string> signatureParams = new List<string>();
// パラメタの生成
string nonce = CreateNonce();
string timeStamp = UnixTime().ToString();
StringBuilder ccparams = new StringBuilder();
// OAuthヘッダの生成
signatureParams.Add("oauth_version=1.0");
signatureParams.Add(string.Format("oauth_timestamp={0}", timeStamp));
signatureParams.Add(string.Format("oauth_nonce={0}", nonce));
signatureParams.Add("oauth_signature_method=HMAC-SHA1");
signatureParams.Add(string.Format("oauth_consumer_key={0}", UrlEncode(ConsumerKey)));
if (!string.IsNullOrEmpty(AccessToken))
{
signatureParams.Add(string.Format("oauth_token={0}", UrlEncode(AccessToken)));
}
foreach (var p in Params)
{
signatureParams.Add(string.Format("{0}={1}", p.Key, UrlEncode(p.Value)));
}
signatureParams.Sort();
foreach (string s in signatureParams)
{
if (ccparams.Length != 0)
ccparams.Append("&");
ccparams.Append(s);
}
// Signatureを生成
string hmacKey = string.Format("{0}&{1}", ConsumerSecret, (string.IsNullOrEmpty(AccessTokenSecret)) ? "" : AccessTokenSecret);
string hmacData = string.Format("{0}&{1}&{2}",
Method, UrlEncode(Url), UrlEncode(ccparams.ToString()));
var hmac = HmacSha1(hmacData, hmacKey);
string signature = Convert.ToBase64String(hmac);
// Authorizeヘッダの生成
string authorize = string.Format(
@"OAuth oauth_consumer_key=""{0}"",oauth_timestamp=""{1}"",oauth_nonce=""{2}"",oauth_signature=""{3}"",oauth_signature_method=""HMAC-SHA1"",oauth_version=""1.0""",
UrlEncode(ConsumerKey), UrlEncode(timeStamp), UrlEncode(nonce), UrlEncode(signature));
if (!string.IsNullOrEmpty(AccessToken))
authorize += string.Format(@",oauth_token=""{0}""", AccessToken);
return authorize;
}
string ConcatParams(Dictionary<string, string> Params)
{
StringBuilder ccparams = new StringBuilder();
foreach (var s in Params)
{
if (ccparams.Length != 0)
ccparams.Append("&");
ccparams.Append(string.Format("{0}={1}", s.Key, UrlEncode(s.Value)));
}
return ccparams.ToString();
}
#endregion
HttpWebRequest CreateRequest()
{
string reqUrl = Url;
if (Params == null) Params = new Dictionary<string, string>();
if (Method != RequestMethod.Post && Params.Count != 0)
reqUrl += string.Format("?{0}", ConcatParams(Params));
string authorization = CreateAuthorizeHeader(Url, Method == RequestMethod.Post ? "POST" : "GET", Params);
var client = (HttpWebRequest)WebRequest.Create(reqUrl);
client.Headers["Authorization"] = authorization;
client.Method = Method == RequestMethod.Post ? "POST" : "GET";
return client;
}
#if NETFX_CORE
async Task<HttpWebResponse> GetResponse(HttpWebRequest client)
{
if (Method == RequestMethod.Post)
{
var stream = await client.GetRequestStreamAsync();
var bytes = Encoding.UTF8.GetBytes(ConcatParams(Params));
stream.Write(bytes, 0, bytes.Length);
await stream.FlushAsync();
}
return (HttpWebResponse) await client.GetResponseAsync();
}
#else
HttpWebResponse GetResponse(HttpWebRequest client)
{
if (Method == RequestMethod.Post)
{
var stream = client.GetRequestStream();
var bytes = Encoding.UTF8.GetBytes(ConcatParams(Params));
stream.Write(bytes, 0, bytes.Length);
stream.Close();
}
return (HttpWebResponse)client.GetResponse();
}
#endif
/// <summary>
/// OAuthでリクエストを送信する
/// </summary>
public Task<HttpWebResponse> GetResponseAsync()
{
var client = CreateRequest();
// Send Request
return GetResponse(client);
}
public async Task<string> GetResponseTextAsync()
{
var client = CreateRequest();
// Send Request
HttpWebResponse resp = await GetResponse(client);
var respStream = resp.GetResponseStream();
var sr = new StreamReader(respStream);
var text = sr.ReadToEnd();
return text;
}
private HttpWebRequest bufferedRequest_;
private StreamReader bufferedReader_ = null;
public async Task<string> GetResponseTextLineAsync()
{
if (bufferedReader_ == null)
{
bufferedRequest_ = CreateRequest();
// Send Request
HttpWebResponse resp = await GetResponse(bufferedRequest_);
var respStream = resp.GetResponseStream();
bufferedReader_ = new StreamReader(respStream);
}
try
{
return await bufferedReader_.ReadLineAsync();
}
catch (WebException)
{
return null;
}
}
/// <summary>
/// OAuthEchoで必要なAuthorizationヘッダを生成する
/// </summary>
/// <param name="Url">アクセスするURL。通常http://.../verify_credential</param>
/// <param name="Method">アクセスするメソッド</param>
/// <param name="Params">追加の引数</param>
/// <returns></returns>
public string GetRequestAuthorization(string Url, string Method, Dictionary<string, string> Params)
{
return CreateAuthorizeHeader(Url, Method, Params);
}
public OAuthClient()
{
}
public OAuthClient(string consumerKey, string consumerSecret, string accessToken, string accessTokenSecret)
{
ConsumerKey = consumerKey;
ConsumerSecret = consumerSecret;
AccessToken = accessToken;
AccessTokenSecret = accessTokenSecret;
}
}
}
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment