2010年5月3日月曜日

DotNetOpenAuth でサンプルコード

サンプルはシンプルがいいよね。

OAuth の公式ページ、OAuth — An open protocol to allow secure API authorization in a simple and standard method from desktop and web applications.Code で、.NET Framework 向けのライブラリとして最初に掲示されてる DotNetOpenAuth

ライセンスも Microsoft Public License (Ms-PL) で提供されてるので、いいじゃんと思って使おうとしたら、サンプルコードがやたらがっつり書いてある。

こういうのは、処理の流れがわかる最低限の部分がわかればいいんだろうなと思いましたので、シンプルなサンプル、書いてみました。ちょうど Twitter の認証方式が OAuth に一本化されるということなので、今回はそれ向けで。(^^♪

利用する場合は以下のライブラリが必要になります。ありがたく使わせていただきますm(_ _)m
DotNetOpenAuth
 http://www.dotnetopenauth.net/
Apache log4net - Apache log4net: Home
 http://logging.apache.org/log4net/index.html


1. サンプルソース - DotNetOpenAuthSimpleSample -
サンプルは、GET statuses/home_timeline | dev.twitter.com の API をたたくもの。ここでは主要なクラスのみ紹介。

メイン
Program.cs
XmlSerializer に Parse させようとしている statuses クラスは、いったん API に生の XML を吐かせて Xsd.exe で XSD のガワを作成→少し整形 した自動生成コード。

using System;
using System.Diagnostics;
using System.Xml.Serialization;
using DotNetOpenAuth.Messaging;

namespace DotNetOpenAuthSimpleSample
{
class Program
{
static void Main(string[] args)
{
var statusesHomeTimeline = new MessageReceivingEndpoint(
"http://api.twitter.com/1/statuses/home_timeline.xml", HttpDeliveryMethods.GetRequest);

using (var resourceResponse = statusesHomeTimeline.Open(Verify))
using (var responseStream = resourceResponse.GetResponseReader())
{
var xmlSerializer = new XmlSerializer(typeof(statuses));
var statuses = (statuses)xmlSerializer.Deserialize(responseStream);

foreach (var status in statuses.status)
{
Console.WriteLine(
string.Format("User: {0}, Text: {1}, Location: {2}",
status.user.name, status.text, status.user.location));
}
}

Console.ReadLine();
}

private static string Verify(Uri authorizationLocation)
{
Process.Start(authorizationLocation.AbsoluteUri);
Console.Write("Please enter PIN code: ");
return Console.ReadLine();
}
}
}



Twitter 向け Consumer
TwitterConsumer.cs
ServiceProviderDescription を各サービス向けに書き換えれば良い。ThreadStatic になってるのは、自分の用途として、マルチスレッドで別々の認証情報を扱いながら処理を進めるってことが多いから。

using System;
using System.Collections.Generic;
using System.Configuration;
using System.Net;
using DotNetOpenAuth.Messaging;
using DotNetOpenAuth.OAuth;
using DotNetOpenAuth.OAuth.ChannelElements;

namespace DotNetOpenAuthSimpleSample
{
public static class TwitterConsumer
{
public delegate string VerifyCallback(Uri authorizationLocation);

[ThreadStatic]
private static ServiceProviderDescription serviceProviderDescription;

private static ServiceProviderDescription ServiceProviderDescription
{
get
{
if (serviceProviderDescription == null)
{
serviceProviderDescription = new ServiceProviderDescription
{
RequestTokenEndpoint = new MessageReceivingEndpoint("https://twitter.com/oauth/request_token",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
UserAuthorizationEndpoint = new MessageReceivingEndpoint("https://twitter.com/oauth/authorize",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
AccessTokenEndpoint = new MessageReceivingEndpoint("https://twitter.com/oauth/access_token",
HttpDeliveryMethods.GetRequest | HttpDeliveryMethods.AuthorizationHeaderRequest),
TamperProtectionElements = new ITamperProtectionChannelBindingElement[] { new HmacSha1SigningBindingElement() },
ProtocolVersion = ProtocolVersion.V10a,
};
}

return serviceProviderDescription;
}
}

public static bool IsConfigured
{
get
{
return !string.IsNullOrEmpty(ConfigurationManager.AppSettings["consumerKey"]) &&
!string.IsNullOrEmpty(ConfigurationManager.AppSettings["consumerSecret"]);
}
}

[ThreadStatic]
private static DesktopConsumer current;

private static DesktopConsumer Current
{
get
{
if (current == null)
{
if (IsConfigured)
{
var tokenManager = new InMemoryTokenManager();
tokenManager.ConsumerKey = ConfigurationManager.AppSettings["consumerKey"];
tokenManager.ConsumerSecret = ConfigurationManager.AppSettings["consumerSecret"];
current = new DesktopConsumer(ServiceProviderDescription, tokenManager);
}
else
{
throw new InvalidOperationException(
"No Twitter OAuth consumer key and secret could be found in App.config AppSettings.");
}
}

return current;
}
}

[ThreadStatic]
private static string accessToken;

public static IncomingWebResponse Open(this MessageReceivingEndpoint endpoint, VerifyCallback verify)
{
return Open(endpoint, verify, default(object));
}

public static IncomingWebResponse Open(
this MessageReceivingEndpoint endpoint, VerifyCallback verify, IDictionary<string, string> extraData)
{
return Open(endpoint, verify, extraData);
}

public static IncomingWebResponse Open(
this MessageReceivingEndpoint endpoint, VerifyCallback verify, IEnumerable<MultipartPostPart> binaryData)
{
return Open(endpoint, verify, binaryData);
}

private static IncomingWebResponse Open(this MessageReceivingEndpoint endpoint, VerifyCallback verify, object data)
{
if (accessToken == null)
{
string requestToken = null;
Uri authorizationLocation = Current.RequestUserAuthorization(null, null, out requestToken);
string verifier = verify(authorizationLocation);
var grantedAccess = Current.ProcessUserAuthorization(requestToken, verifier);
accessToken = grantedAccess.AccessToken;
}

HttpWebRequest request = null;
IDictionary<string, string> extraData = null;
IEnumerable<MultipartPostPart> binaryData = null;

if ((extraData = data as IDictionary<string, string>) != null)
{
request = Current.PrepareAuthorizedRequest(endpoint, accessToken, extraData);
}
else if ((binaryData = data as IEnumerable<MultipartPostPart>) != null)
{
request = Current.PrepareAuthorizedRequest(endpoint, accessToken, binaryData);
}
else
{
request = Current.PrepareAuthorizedRequest(endpoint, accessToken);
}

return Current.Channel.WebRequestHandler.GetResponse(request);
}
}
}





2. ダウンロード
ソリューション全体のダウンロードは こちら



Arduino 、Android、GAE とか新しいことやり始めて、改めてサンプルの大切さ、学んでます。( ..)φメモメモ