1. ホーム
  2. .net

[解決済み] .NETでの検証付きOAuth

2022-12-21 13:22:26

質問

私は、OAuth 対応のアプリケーション、特に Mendeley (現在はコンソール アプリとして使用しています) と統合するための .NET ベースのクライアント アプリを (WPF で) 作成しようとしています。 http://dev.mendeley.com ) と統合します。

OAuth を使用するのは初めてですが、使い始めるのにかなり苦労しています。いくつかの .NET OAuth ライブラリまたはヘルパーを見つけましたが、それらは私が必要と思うより複雑なようです。私がしたいことは、Mendeley APIにRESTリクエストを発行し、応答を取得することです!

今のところ、私は試してみました。

最初のもの (DotNetOpenAuth) は、私が何時間もかけて方法を見つけ出そうとすれば、必要なことができるように思えるのです。2番目と3番目は、私が知る限り、Mendeley が送り返す検証コードをサポートしていません。)

私はMendeleyからコンシューマーキーとシークレットを入手し、DotNetOpenAuthで、ユーザーがアプリケーションに入力するための検証コードを提供するMendeleyページでブラウザを起動させることに成功しました。しかし、この時点で迷子になり、アプリケーションに戻る検証コードを賢明に提供する方法を見つけることができませんでした。

私は、どこから始めればよいのか全くわからないことを喜んで認めます (かなり急な学習曲線があるように見えますが)。

どのように解決するのですか?

私はあなたに同意します。 .NET アプリで利用できるオープンソースの OAuth サポート クラスは、理解しにくい、過度に複雑 (DotNetOpenAuth が公開しているメソッドはいくつあるか)、お粗末 (あなたが提供した google リンクから OAuthBase.cs モジュールの 10 の文字列パラメーターのメソッドをご覧ください - 状態管理がまったくありません)、またはその他不満な点ばかりです。

こんなに複雑である必要はないのです。

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

おさらいですが、OAuth 1.0aでは...ちょっと面白いことに、特別な名前があって、"standard"のように見えますが、私が知る限り、"OAuth 1.0a" を実装するサービスはTwitterのみです。 標準なんだろうけど 十分 OAuth 1.0aでは、以下のように動作します。 デスクトップアプリケーションの場合 はこうです。

  1. アプリの開発者であるあなたは、アプリを登録し、"consumer key" と "consumer secret" を取得します。 Arstechnicaでは なぜこのモデルがベストではないのかについて、よく書かれた分析があります。 しかし、よく言われるように それはそれである .

  2. アプリが実行されます。初回実行時には、アプリがTwitterとその姉妹サービス(TwitPicなど)に対して自動認証のRESTリクエストを行うことについて、ユーザーから明示的に承認を得る必要があります。これを行うには、ユーザーによる明示的な承認を含む承認プロセスを経る必要があります。これは、アプリを最初に実行するときにのみ発生します。 このように

    • リクエストトークンを要求します。 別名、テンポラリートークン。
    • クエリパラメータとしてリクエストトークンを渡し、Web ページをポップします。 このWebページでは、ユーザーにUIを提示し、「このアプリへのアクセスを許可しますか」と尋ねます。
    • ユーザーは twitter の Web ページにログインし、アクセスを許可または拒否します。
    • 応答HTMLページが表示されます。 ユーザーがアクセスを許可した場合、48ptのフォントでPINが表示されます。
    • ユーザーは、その PIN を Windows のフォーム ボックスに切り取り/貼り付け、"Next" または同様のものをクリックする必要があります。
    • デスクトップ アプリは、quot;Access token" のための自動認証要求を行います。 別の REST リクエストです。
    • デスクトップアプリは、アクセストークンとアクセシークレットを受け取ります。

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


巧妙でない場合、UI フローは複数ステップの OAuth メッセージ フローをミラーリングするようなものです。 もっと良い方法があります。

WebBrowser コントロールを使用し、デスクトップ アプリ内で認証 Web ページを開きます。 ユーザーが [許可] をクリックすると、WebBrowser コントロールから応答テキストを取得し、PIN を自動的に抽出して、アクセストークンを取得します。 5~6回のHTTPリクエストを送信しますが、ユーザーが見る必要があるのは、1つのAllow/Denyダイアログだけです。 シンプルですね。

このように


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, token_secret, nonce, timestamp, consumer_key, version, and callback) を特定の方法 (url-encoded and joined by ampersand) で辞書順にまとめ、その結果に対して署名を生成し、同じパラメータと署名とを別の方法 (joined by commas) で新しい oauth_signature パラメータに格納する必要があると述べています。 OAuthマネージャクラスは、あなたのためにこれを自動的に行います。 これはnoncesとタイムスタンプとバージョンを生成します。 と署名 を自動的に生成します。あなたのアプリはそのようなものを気にしたり、意識したりする必要はありません。 oauth パラメータの値を設定し、シンプルなメソッドを呼び出すだけです。マネージャクラスはリクエストを送信し、あなたのためにレスポンスを解析します。

OK, then what? リクエストトークンを取得したら、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コントロールは自動的にそのページに移動するようになります。

ユーザーが "Allow"ボタンをクリックすると、新しいページがロードされます。これは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 呼び出しで、上で説明した 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 "となります。

というHTTPヘッダにその文字列を設定します。 認証 .

TwitPic のようなサードパーティーのサービスとやりとりするためには、TwitPic のようなサードパーティーのサービスに対して 若干異なる OAuthヘッダーを作成する必要があります。

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

Twitterの場合、verify creds urlとrealmの値は"です。 https://api.twitter.com/1/account/verify_credentials.json "、および " http://api.twitter.com/ "それぞれです。

...そして その という HTTP ヘッダに認可文字列を記述します。 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フォームの例を参照してください。 ここで .


動作例

動作例のダウンロード をダウンロードしてください。