.NETでの検証を伴うOAuth


103

OAuth対応のアプリケーション、特にMendeley(http:// dev .mendeley.com)、明らかに3-legged OAuthを使用しています。

OAuthを使用するのは今回が初めてで、OAuthの使用を開始するのに非常に苦労しています。.NET OAuthライブラリまたはヘルパーをいくつか見つけましたが、必要以上に複雑に見えます。私がやりたいのは、Mendeley APIにRESTリクエストを発行して、応答を返すことができることです!

これまでのところ、私は試しました:

最初の(DotNetOpenAuth)は、何時間も費やしてその方法を考え出せば、おそらく私が必要とすることを実行できるようです。2つ目と3つ目は、よくわかるように、Mendeleyが送り返している確認コードをサポートしていません-これについては間違っているかもしれませんが:)

私はMendeleyからコンシューマーキーとシークレットを取得しました。DotNetOpenAuthを使用して、ユーザーがアプリケーションに入力するための確認コードを提供するMendeleyページでブラウザーを起動することができました。しかし、この時点で私は迷子になり、それをアプリケーションに適切に提供する方法を理解できませんでした。

私はこれからどこから始めればよいかわからないことを認めたいと思っています(ただし、かなり急な学習曲線があるようです)。誰かが私を正しい方向に向けることができれば、感謝します!

回答:


182

仰るとおりです。.NETアプリで利用できるオープンソースのOAuthサポートクラスは理解が難しく、複雑すぎ(DotNetOpenAuthで公開されているメソッドの数はいくつですか)、設計が不十分です(GoogleのOAuthBase.csモジュールで10個の文字列パラメーターを持つメソッドを見てください)提供したリンク-状態管理はまったくありません)、またはそれ以外の場合は不十分です。

これは複雑である必要はありません。

私はOAuthの専門家ではありませんが、TwitterやTwitPicでうまく使用できるOAuthクライアント側マネージャークラスを作成しました。使い方は比較的簡単です。オープンソースであり、こちらから入手できます:Oauth.cs

復習すると、OAuth 1.0aにはちょっとおかしい、特別な名前があり、それは「標準」のように見えますが、私が知る限り、「OAuth 1.0a」を実装する唯一のサービスはTwitterです。それで十分だと思います。とにかく、OAuth 1.0aでは、デスクトップアプリでの動作は次のとおりです

  1. アプリの開発者であるあなたは、アプリを登録し、「コンシューマキー」と「コンシューマシークレット」を取得します。Arstechnicaには、なぜこのモデルが最適ないのかについてのよく書かれた分析がありますが、彼らが言うように、それはそれが何であるかです

  2. アプリが実行されます。初めて実行するときは、アプリに明示的に承認を付与して、Twitterとその姉妹サービス(TwitPicなど)にoauth認証されたRESTリクエストを送信する必要があります。これを行うには、ユーザーによる明示的な承認を含む承認プロセスを実行する必要があります。これは、アプリを初めて実行したときにのみ発生します。このような:

    • 「リクエストトークン」をリクエストします。別名一時トークン。
    • Webページをポップし、そのリクエストトークンをクエリパラメータとして渡します。このWebページは、ユーザーにUIを表示し、「このアプリへのアクセスを許可しますか?」
    • ユーザーはTwitterのWebページにログインし、アクセスを許可または拒否します。
    • 応答HTMLページが表示されます。ユーザーがアクセスを許可した場合、48-ptフォントで表示されたPINがあります。
    • 次に、ユーザーはそのピンをWindowsフォームボックスにカットアンドペーストし、[次へ]または同様のものをクリックする必要があります。
    • 次に、デスクトップアプリが「アクセストークン」のoauth認証済みリクエストを実行します。別のRESTリクエスト。
    • デスクトップアプリは「アクセストークン」と「アクセスシークレット」を受け取ります。

承認ダンスの後、デスクトップアプリはユーザー固有の「アクセストークン」と「アクセスシークレット」を(アプリ固有の「コンシューマキー」と「コンシューマシークレット」とともに)使用して、ユーザーに代わって認証済みリクエストを実行できますTwitterへ。これらは期限切れになりませんが、ユーザーがアプリの認証を解除した場合、または何らかの理由でTwitterがアプリの認証を解除した場合、またはアクセストークンやシークレットを紛失した場合は、もう一度承認ダンスを行う必要があります。 。


賢くなければ、UIフローはマルチステップOAuthメッセージフローをミラーリングすることができます。もっと良い方法があります。

WebBrowserコントロールを使用して、デスクトップアプリ内で承認Webページを開きます。ユーザーが[許可]をクリックすると、そのWebBrowserコントロールから応答テキストを取得し、PINを自動的に抽出して、アクセストークンを取得します。5つまたは6つのHTTPリクエストを送信しますが、ユーザーは単一の許可/拒否ダイアログを見るだけで済みます。シンプル。

このような:
代替テキスト


UIを並べ替えた場合、残っている唯一の課題は、oauth署名付きリクエストを生成することです。これは、oauth署名の要件が特別なものであるため、多くの人をつまずかせます。これが、簡素化されたOAuth Managerクラスが行うことです。

トークンをリクエストするコードの例:

var oauth = new OAuth.Manager();
// the URL to obtain a temporary "request token"
var rtUrl = "https://api.twitter.com/oauth/request_token";
oauth["consumer_key"] = MY_APP_SPECIFIC_KEY;
oauth["consumer_secret"] = MY_APP_SPECIFIC_SECRET;    
oauth.AcquireRequestToken(rtUrl, "POST");

それだ。シンプル。コードからわかるように、oauthパラメーターにアクセスするには、辞書のような文字列ベースのインデクサーを使用します。AcquireRequestTokenメソッドは、リクエストトークン、つまり一時トークンを付与するサービスのURLにoauth署名付きリクエストを送信します。Twitterの場合、このURLは「https://api.twitter.com/oauth/request_token」です。oauth仕様では、oauthパラメータ(トークン、token_secret、nonce、タイムスタンプ、consumer_key、バージョン、およびコールバック)のセットを、特定の方法(URLエンコードしてアンパサンドで結合)、および辞書順でパックする必要があると述べていますソートされた順序で、その結果に署名を生成し、新しいパラメーターをコンマで結合して、新しいoauth_signatureパラメーターに格納されている署名と一緒にそれらの同じパラメーターをパックします。 OAuthマネージャークラスは、これを自動的に行います。 それはナンスとタイムスタンプとバージョンと署名を自動的に生成します-あなたのアプリはそのことを気にする必要はありません。oauthパラメータ値を設定し、簡単なメソッド呼び出しを行うだけです。マネージャークラスはリクエストを送信し、レスポンスを解析します。

じゃあなに?要求トークンを取得したら、ユーザーが明示的に承認を付与するWebブラウザーUIをポップします。これを正しく行うと、埋め込みブラウザーでこれをポップします。Twitterの場合、このURLは「https://api.twitter.com/oauth/authorize?oauth_token=」で、oauth_tokenが追加されています。このようにコードでこれを行います:

var url = SERVICE_SPECIFIC_AUTHORIZE_URL_STUB + oauth["token"];
webBrowser1.Url = new Uri(url);

(これを外部ブラウザーで行っている場合は、を使用しますSystem.Diagnostics.Process.Start(url)。)

Urlプロパティを設定すると、WebBrowserコントロールがそのページに自動的に移動します。

ユーザーが[許可]ボタンをクリックすると、新しいページが読み込まれます。これはHTMLフォームで、フルブラウザと同じように機能します。コードで、WebBrowserコントロールのDocumentedCompletedイベントのハンドラーを登録し、そのハンドラーでピンを取得します。

var divMarker = "<div id=\"oauth_pin\">"; // the div for twitter's oauth pin
var index = webBrowser1.DocumentText.LastIndexOf(divMarker) + divMarker.Length;
var snip = web1.DocumentText.Substring(index);
var pin = RE.Regex.Replace(snip,"(?s)[^0-9]*([0-9]+).*", "$1").Trim();

これは、HTML画面のスクレイピングです。

ピンをつかんだ後は、Webブラウザーは必要ありません。

webBrowser1.Visible = false; // all done with the web UI

...そして、Dispose()を呼び出すこともできます。

次のステップは、そのピンとともに別のHTTPメッセージを送信することにより、アクセストークンを取得することです。これは、上記で説明したoauthの順序とフォーマットで構成された、もう1つの署名付きoauth呼び出しです。ただし、これもOAuth.Managerクラスを使用すると非常に簡単です。

oauth.AcquireAccessToken(URL_ACCESS_TOKEN,
                         "POST",
                         pin);

Twitterの場合、そのURLは「https://api.twitter.com/oauth/access_token」です。

これでアクセストークンが取得され、署名済みHTTPリクエストでそれらを使用できます。このような:

var authzHeader = oauth.GenerateAuthzHeader(url, "POST");

... urlリソースのエンドポイントはどこですか。ユーザーのステータスを更新するには、「http://api.twitter.com/1/statuses/update.xml?status=Hello」のようになります。

次に、その文字列をAuthorizationという名前のHTTPヘッダーに設定します。

TwitPicなどのサードパーティサービスとやり取りするには、次のように少し異なる OAuthヘッダーを作成する必要があります。

var authzHeader = oauth.GenerateCredsHeader(URL_VERIFY_CREDS,
                                            "GET",
                                            AUTHENTICATION_REALM);

Twitterの場合、クレデンシャルの検証URLとレルムの値は、それぞれ「https://api.twitter.com/1/account/verify_credentials.json」と「http://api.twitter.com/」です。

...そしてその認証文字列をX-Verify-Credentials-Authorizationと呼ばれるHTTPヘッダーに入れます。次に、それを、送信する要求と一緒にTwitPicなどのサービスに送信します。

それでおしまい。

まとめると、Twitterステータスを更新するコードは次のようになります。

// the URL to obtain a temporary "request token"
var rtUrl = "https://api.twitter.com/oauth/request_token";
var oauth = new OAuth.Manager();
// The consumer_{key,secret} are obtained via registration
oauth["consumer_key"] = "~~~CONSUMER_KEY~~~~";
oauth["consumer_secret"] = "~~~CONSUMER_SECRET~~~";
oauth.AcquireRequestToken(rtUrl, "POST");
var authzUrl = "https://api.twitter.com/oauth/authorize?oauth_token=" + oauth["token"];
// here, should use a WebBrowser control. 
System.Diagnostics.Process.Start(authzUrl);  // example only!
// instruct the user to type in the PIN from that browser window
var pin = "...";
var atUrl = "https://api.twitter.com/oauth/access_token";
oauth.AcquireAccessToken(atUrl, "POST", pin);

// now, update twitter status using that access token
var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello";
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);

using (var response = (HttpWebResponse)request.GetResponse())
{
    if (response.StatusCode != HttpStatusCode.OK)
        MessageBox.Show("There's been a problem trying to tweet:" +
                        Environment.NewLine +
                        response.StatusDescription);
}

OAuth 1.0aは内部的には少し複雑ですが、使用する必要はありません。OAuth.Managerは、発信oauthリクエストの生成と、応答内のoauthコンテンツの受信と処理を処理します。Request_tokenリクエストがoauth_tokenを提供する場合、アプリはそれを保存する必要はありません。Oauth.Managerは、それを自動的に実行するのに十分スマートです。同様に、access_tokenリクエストがアクセストークンとシークレットを取得する場合、それらを明示的に保存する必要はありません。OAuth.Managerがその状態を処理します。

以降の実行では、アクセストークンとシークレットがすでにある場合、次のようにOAuth.Managerをインスタンス化できます。

var oauth = new OAuth.Manager();
oauth["consumer_key"] = CONSUMER_KEY;
oauth["consumer_secret"] = CONSUMER_SECRET;
oauth["token"] = your_stored_access_token;
oauth["token_secret"] = your_stored_access_secret;

...次に、上記のように認証ヘッダーを生成します。

// now, update twitter status using that access token
var appUrl = "http://api.twitter.com/1/statuses/update.xml?status=Hello";
var authzHeader = oauth.GenerateAuthzHeader(appUrl, "POST");
var request = (HttpWebRequest)WebRequest.Create(appUrl);
request.Method = "POST";
request.PreAuthenticate = true;
request.AllowWriteStreamBuffering = true;
request.Headers.Add("Authorization", authzHeader);

using (var response = (HttpWebResponse)request.GetResponse())
{
    if (response.StatusCode != HttpStatusCode.OK)
        MessageBox.Show("There's been a problem trying to tweet:" +
                        Environment.NewLine +
                        response.StatusDescription);
}

OAuth.Managerクラスを含むDLLはこちらからダウンロードできます。そのダウンロードにはヘルプファイルもあります。または、オンラインでヘルプファイル表示できます

このマネージャを使用するWindowsフォームの例をここで参照してください


使用例

ここで説明するクラスと手法を使用するコマンドラインツールの実際の例ダウンロードします。


こんにちは、ご回答ありがとうございます。私は実際にOAuthから移行しました(私はMendeleyをあきらめ、代替案を採用しました)。また、あなたが書いたクラスを今後必要になるときにブックマークしました。改めて感謝いたします。
ジョン

2
こんにちはCheeso、コードと詳細な説明を共有していただきありがとうございます。優れたシンプルなソリューションを提供しました。ただし、GetSignatureBaseメソッドに小さな変更を加えて、「oob」以外のソリューションをサポートする必要があります。「oob」以外の場合は、コールバックをURLエンコードする必要があるため、this._paramsを反復処理するときに、次のようなものを追加する必要があります。if(p1.Key == "callback"){p.Add( "oauth_" + p1.Key、UrlEncode(p1.Value)); continue;}
Johnny

1
これはOAuth 2.0では機能しません。このクラスはOAuth 1.0a用です。さまざまなパラメーターの署名や辞書式ソートがないため、OAuth2.0は非常に使いやすくなっています。したがって、おそらくOAuth 2.0を実行するために外部クラスは必要ありません。外部クラスが必要な場合は、このクラスよりもはるかに単純になります。
Cheeso

1
helpfile online not found: cheeso.members.winisp.net/OAuthManager1.1
Kiquenet

3
すべてのリンクが壊れているように見えます。ここでコピーを見つけました:gist.github.com/DeskSupport/2951522#file-oauth-cs
John
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.