
相互認証の例
2005年に戻り、ソーシャルネットワークを作成していると想像します。 Gmailのアドレス帳から連絡先をインポートするためのフォームがあります。 Gmailの連絡先にアクセスするには何が必要ですか? もちろん、ボックスのユーザー名とパスワード。 しかし、私たちがウェブサイトでそれらを入力するように頼むならば、ユーザーは何かが間違っていると疑います。 入力したパスワードをサーバーに保存しないという保証はどこにありますか? したがって、パスワードはGMail Webサイトでのみ入力し、その後、GMail APIを介した連絡先へのアクセスがソーシャルネットワークに提供されるようにします(場合によっては)。
次のようになります。フォームは、「連絡先のインポート」という1つのボタンで構成されています。 クリックすると、ユーザーは一時的にGMailにリダイレクトされ、そこでユーザー名とパスワードを入力します(既に認証されている場合は何も入力しません)。 その後、ユーザーは当社のWebサイトに戻り、スクリプトはすでに内部GMail APIを介して連絡先をダウンロードする機会を得ています。 |
- 消費者 :消費者。 ソーシャルネットワークで連絡先をインポートするフォームを処理するためのスクリプト。
- サービスプロバイダー :データプロバイダー。 GMail。消費者が関心を持つアドレス帳データが含まれています。
- ユーザー :コンシューマーとサービスプロバイダーの両方のアカウントを持っているユーザー。
- 保護されたリソース :個人データ。 Gmailのアドレス帳の連絡先(サービスプロバイダーのリソースなど)。
- プロバイダーAPI :任意のスクリプトがGMailアドレス帳から連絡先を取得できるようにするGMail API。
ここで、画面の上部を紙で閉じて、質問として質問に答えてください:サービスプロバイダーは誰ですか? 保護されたリソースとは何ですか? 消費者とはどのようなもので、ユーザーとどう違うのですか? APIはどこにありますか? さらに記事では、これらの条件を自由に使用します。 あなたがそれらに今十分でない場合、理解に問題があるかもしれません。 |
OAuthとOpenIDの違いは何ですか?
OAuthは「ロボット用プロトコル」と呼ばれることが多く、OpenIDとは異なり、「ユーザー用プロトコル」と呼ばれます。 それらを混同しないでください!
- OpenIDは、登録を加速するためのプロトコルです。 OpenIDを使用すると、ユーザーは、インターネット上の別の場所に既に登録されている場合、パスワードを入力せずにサービスのアカウントを入力できます。 (そして、「どこか」で認証されて、パスワードを入力せずにサービスに入ることができます。)たとえば、Yandexにアカウントがある場合、OpenID認証をサポートするサービスに「ログイン」できます。
- OAuthは、サードパーティAPIへの承認されたアクセスのためのプロトコルです。 OAuthを使用すると、ユーザーが許可した場合、コンシューマースクリプトはサードパーティのサービスプロバイダーデータへのAPIアクセスを制限できます。 つまり これは、APIにアクセスするためのツールです。
警察のアナロジーあなたが1973年のWebMoney窃盗事件の終結を求めている犯罪捜査局の従業員であると想像してください。 条件に同意します。
|
この記事の概要
主要部分に移る前に、どのように正確に移動するかを見てみましょう。
- 相互認証の「手動」実装で発生する問題を考慮してください。
- 「アプリケーション」とは何か、消費者は誰かについて話しましょう。
- 暗号化の基本に触れましょう。
- この記事で作成するデモアプリケーションを示します。
- 実験するOAuthテストサーバーを決定します。
- OAuthプロトコルのすべての手順を実行して、スクリプトのソースを提供します。
自転車の発明について
何かを理解する良い方法は、すべてのスプレッドレーキに沿って自分でそれを行うことです。 次に、車輪を再発明します。標準化されたプロトコルなしで、コンシューマとサービスプロバイダ間の相互作用の問題をどのように解決するか想像してみてください。
最初に、GMail自体を使用して連絡先をインポートするためのフォームを作成します。
コードリスト1:Velocityインポート連絡先 |
<form action = "http://gmail.com/auth.php?retpath=http://oursocialnetwork.ru/import.php" method = "get"> <input type = "submit" value = "Download Address Book" /> </ form> |
そのため、パスワードを入力すると、ユーザーは次のアドレスのWebサイトに戻ります。
コードリスト2:自転車キーリターン自転車アドレス |
http://oursocialnetwork.ru/import.php?secret=Y49xdN0Zo2B5v0RR |
コードリスト3:バイクAPIメソッドの実行 |
$連絡先= $ gmailApi-> getContacts($ _ GET ['secret']); |
Rake First:スプーフィングretpathリターンアドレス
まあ、もちろん、あなたは彼のサイトの攻撃者が最初にリンクを置くと推測しました
コードリスト4:攻撃者のサイト上のリンク |
http://gmail.com/auth.php?retpath=http://hackersite.ru/save.php |
コードリスト5:返信先住所の自転車の秘密 |
http://hackersite.ru/save.php?secret=Y49xdN0Zo2B5v0RR |
2番目の熊手:秘密鍵の「盗聴」
どうにかしてretpathを保護し、今ではそれが私たちのサイトを指すことしかできないとします。 しかし、秘密パラメーターの問題は残っています。
コードリスト6:自転車のキーで自転車の住所を返す |
http://oursocialnetwork.ru/import.php?secret=Y49xdN0Zo2B5v0RR |
秘密キーはURLで送信されるだけでなく、APIメソッドを呼び出すときにも送信されることに注意してください。 傍受も可能です。 もちろん、ここでSSLを使用すると役立ちます。 |
レーキ3番目:リダイレクトが多すぎる
API呼び出しごとに異なるシークレットが必要な場合は、呼び出しと同数のサービスプロバイダーWebサイトへのリダイレクトを整理する必要があります。 APIを集中的に使用すると、これは非常に遅く、順番に不快になります...
レーキ4:消費者の悪い識別
もちろん、GMailは誰がそのAPIを使用しているかを知りたがっています。 あるサイトへのアクセスを許可し、別のサイトへのアクセスを拒否します。したがって、連絡先をインポートする形式でリクエストを生成する場合、コンシューマー(サイト)はサービスプロバイダー(GMail)に「提示」する必要があります。 この場合、この機能はretpath(その中のサイト名)によって部分的に実行されますが、この方法は普遍的ではありません。 APIメソッドを呼び出すときに「プレゼンテーション」メカニズムも呼び出す必要があります。
OAuth Foundation
「水中の熊手」がまだたくさんあることは注目に値します。 この熊手はマリアナ海溝(深さ10920 m)にあるため、ここでは説明しません。 脆弱性の説明には、数十ページを費やす必要があります。 そこで、すべての問題がすでに解決されているOAuthの説明に直接進みます。
OAuthに関する素晴らしい一連の記事があります:OAuthの初心者向けガイド (英語、hueniverseというニックネームを持つ著者から)。 ここまでトピックを完全に理解していない場合、学習するには約4時間かかります。 |
アプリケーション=消費者+ APIアクセス
OAuthを使用する場合、Consumerという用語が「サイト」の意味に限定されないことが重要です。 消費者は特定のアプリケーションであり、その場所はそれほど重要ではありません。 実生活の消費者の例:
- GMailからの連絡先インポートフォームのスクリプト(上記の例を参照)。
- Twitterに投稿できるiPhoneアプリ。
- 最新のチャットメッセージと新しいメッセージを書き込む機能を表示するサイト上の長方形のウィジェット。
トークン=キー+シークレット
OAuthの原則の1つは、リクエストで秘密鍵を公開して送信しないことです(上記の例で理由を調べました)。 したがって、プロトコルはトークンの概念を使用します。 トークンは、ユーザー名とパスワードのペアに非常に似ています。ユーザー名は公開情報であり、パスワードは送信側と受信側のみに知られています。 OAuthの用語では、ログインはKeyと呼ばれ、パスワードはSecretです。 シークレットが送信者と受信者のみに知られ、他の誰にも知られない状況は、共有シークレットと呼ばれます。
そのため、コンシューマとプロバイダが共有シークレットについて何らかの形で合意した場合、これらのキーの傍受が危険になることを恐れずに、URL内の対応するキー(キー)をオープンに交換できます。 しかし、キーを使用してURLを偽造から保護する方法
メッセージ=ドキュメント+デジタル署名
「デジタル署名」-怖いように聞こえますが、実際にはかなり明白なことです。 文書をペンでサインオンすると、この文書が他人によってではなく、あなたによって書かれたことを証明します。 署名はドキュメントに「追加」され、「1セット」で送信されます。
同様に、データブロックにデジタル署名が追加され、このデータを生成した人が別の人になりすましていないことを証明します。 デジタル署名はドキュメントを暗号化せず、信頼性を保証するだけです! 署名を受信者と送信者には知られているが、他の誰にも知られていない非常に共有された秘密に置くことができます。
どのように機能しますか? $ sharedSecret = 529AeGWgとすると、受信側の耳元でささやくように彼に知らせました。 攻撃者による不正行為に対する保護が保証されたメッセージ「My Phone 1234567」を送信します。
- 一般に、消費者はメッセージにデジタル署名を追加します-
$転送= $メッセージ。 「-」。 md5($メッセージ。$ sharedSecret); // $ transfer = "私の電話は1234567"です。 「-」。 md5(「私の電話は1234567です。」「529AeGWg」)
- サービスプロバイダーはデータを受け入れ、それを2つの部分($メッセージと$署名)に分割して戻し、まったく同じ操作を実行します。
$ signatureToMatch = md5($メッセージ。$ sharedSecret); // $ signatureToMatch = md5( "私の電話は1234567"。 "529AeGWg");
残っているのは、結果の$ signatureToMatch値を、受信データに含まれる$ signatureと比較し、値が一致しなかった場合に偽を報告することです。
したがって、MD5署名を作成するには、共有秘密を知っている必要があります。 (ところで、MD5に加えて、他の不可逆的なハッシュアルゴリズムがあります。)攻撃者は共有秘密を知らないため、署名を偽造することはできません。 |
シンプルなアプリケーションを使用したOAuthのデモ
OAuthをライブで体験するには、次の2つが必要です。
- プロトコルのクライアント部分を実装するスクリプト。 このような小さなPHPスクリプトを作成しました( zipアーカイブへのリンク )。 これは、PHPサイトに挿入できるウィジェットです。
- 実験可能なOAuthテストサーバー。 この目的には、RuTvitを使用すると便利です。http://rutvit.ru/apps/newというページがあり、30秒でテストアプリケーションを追加できます。 (ちなみに、フォームの戻りURLは省略できます。テストスクリプトから渡します。)

コードをコピーしてレイアウトを微調整するだけで、このウィジェットを任意のPHPサイトに貼り付けることができます。 指定したハッシュタグでマークされたRuTvitサービスからのすべてのツイートが表示され、新しいツイートを追加することもできます(これはOAuthが使用される場所です)。 ウィジェットはRuTwit APIとOAuth認証を使用しますが、これは偶然、Twitter API標準と一致しています。
現在、PHPでOAuthを操作するためのやや普遍的なライブラリは、Andy SmithによるOAuth.phpのみです。 これには2つの欠点があります:汚く書かれており、1年以上更新されていない。 他のライブラリへのリンクはOAuth Webサイトで提供されていますが、これらのツールはPHP拡張のインストールが必要であるか、粗すぎるか、他のライブラリに外部依存関係があります(Zend Frameworkのドラフトライブラリは非常に有望に見えます)。 彼らが言うように、「マウスは泣き、刺したが、サボテンを食べ続けた」-OAuth.phpを使用します。 |
- スクリプトコードをダウンロードし、Webサーバー上の任意の便利なディレクトリに展開します。
- OAuthサーバーに新しいテストアプリケーションを登録します。
- アプリケーションを登録した後、スクリプトのOA_CONSUMER_KEYおよびOA_CONSUMER_SECRETパラメーターをサーバーから受信した値に置き換えます。
このスクリプトは、OOPを使用せず、可能な限り「額に」書かれています。 2つの目標を追求しました。a)コードの簡潔さとわかりやすさを実現すること、b)コードを記事のストーリーテリングの行と平行にすることです(したがって、この有限状態マシンとswitch ...の場合)。 はい、もう1つ。 OAuth.phpファイルは一般的なものではなく、Andy Smithのライブラリです(変更はありません)。 |
アプリケーション登録とそのパラメーター
アプリケーションがどこから来たのか、そしてサービスプロバイダーがそれらについてどのように見つけたのかについて話しましょう。 すべてが非常に簡単です。サービスプロバイダーには、誰でも使用できる特別なアプリケーション登録フォームがあります。 このフォームの例を次に示します。

アプリケーションを登録すると、OAuthを使用するために必要な5つのパラメーターが与えられます。 それらは次のようになります。

ここで、コンシューマキーとコンシューマシークレットは、アプリケーションの一種の「ユーザー名+パスワード」です(上記のトークンに関する会話を覚えていますか?これはそのうちの1つにすぎません)。 コンシューマシークレットは共有シークレットであり、送信者と受信者のみに知られ、他の誰にも知られていません。 残りの3つの値はサービスのURLを指定しますが、その意味を次に検討します。
コードリスト7:OAuthオプションと変数定義 |
<?php require_once "OAuth.php"; //異なるパラメーター。 define( "ENCODING"、 "windows-1251"); //サイトのエンコード。 UTF-8を使用している場合は、これで完了です。 定義(「TAG」、「サポート」); //ツイートをフィルタリングするタグ。 // OAuthパラメーター。 それらを暗記してください(特にSECRET)。 define( "OA_CONSUMER_KEY"、 "JId0zVAbQCVnqjD9OlvM"); // OAuthアクセスパラメータ。 define( "OA_CONSUMER_SECRET"、 "qocMBQg1P17CBcdVsJizsNPnlGbTU4fvlGxAszmzB5"); define( "OA_URL_REQ_TOK"、 "http://api.rutvit.ru/oauth/request_token"); define( "OA_URL_AUTH_TOK"、 "https://api.rutvit.ru/oauth/authorize"); define( "OA_URL_ACCESS_TOK"、 "http://api.rutvit.ru/oauth/access_token"); |
OAuth =リクエストトークンの取得+承認へのリダイレクト+アクセストークンの取得+ APIの呼び出し
...または、偉大な強大な意味に翻訳されます:
|
そして、多くのセキュリティ上の問題を明らかにしました。これは、さらなる課題があるべきであることを示唆しています。 これがOAuthで発生することです。トークンで動作するコンシューマスクリプトからプロバイダへの中間リクエストが追加されます。 それらを見てみましょう。
コードリスト8:ステートマシンを介した状態遷移の処理 |
// OAuthを使用するには、値を保持する3つの変数が必要です //ページの読み込み間(簡単にするために、セッションに保存します)。 session_start(); $ S_MSG =&$ _ SESSION ['msg']; $ S_REQUEST_TOK =&$ _ SESSION ['REQUEST_TOK']; $ S_ACCESS_TOK =&$ _ SESSION ['ACCESS_TOK']; //パス: // form_is_sent-> // fetch_request_token-> // authorize_request_token(ブラウザ経由)-> // fetch_access_token(request_tokenをaccess_tokenと交換)-> // send_msg(API経由) //または: // form_is_sent-> // send_msg(API経由) $ action = @ $ _ GET ['action']; while($アクション){ スイッチ($アクション){ |
- フォーム送信の処理。 これはOAuthの一部ではなく、アプリケーションの一部です。 プロバイダーAPIに連絡する前に、このアクションの注文をこのユーザーから受け取る必要があります。 このような「注文」の例を次に示します。
コードリスト9:フォーム送信の処理 // 1.フォームの送信が要求されました。 開始するステップを決定します。 // OAuthを使用するか、APIを介してメッセージを送信します。 ケース 'form_is_sent':{ //メッセージをセッションに保存します。後で必要になります。 $ S_MSG = $ _POST ['msg']; if($ S_ACCESS_TOK && $ S_ACCESS_TOK-> secret){ //ユーザーは現在のセッションで既にコメントを投稿しています。 $ action = 'send_msg'; } else { //承認はまだ実行されていません。OAuthプロシージャを開始します。 $ action = 'fetch_request_token'; } 休憩; }
- フェッチリクエストトークン(内部リクエスト)。
- コンシューマスクリプトは、プロバイダーのリクエストトークンURLにアクセスします(例: api.rutvit.ru/oauth/request_token) 。 リクエストはコンシューマキー(「アプリケーションログイン」)を渡し、リクエスト自体はコンシューマシークレット(「アプリケーションパスワード」)を使用して署名され、偽造から保護されます。
- 応答として、プロバイダーはリクエストトークンと呼ばれる「ガベージで満たされた」トークンを生成して返します。 まだ便利なので、どこかに保存する必要があります-たとえば、$ S_REQUEST_TOKセッション変数に保存します。
コードリスト10:リクエストトークンの取得 // 2.リクエストトークンの受信をリクエスト。 //ソケットを介してサービスプロバイダーにアクセスし、トークンを取得します。 case 'fetch_request_token':{ //リクエストトークンのリクエストを生成します。 $ consumer =新しいOAuthConsumer(OA_CONSUMER_KEY、OA_CONSUMER_SECRET); $ req = OAuthRequest :: from_consumer_and_token( $コンシューマー、NULL、 「GET」、「http://api.rutvit.ru/oauth/request_token」 ); //リクエストにデジタル署名を追加して、偽造されないようにします。 $ req-> sign_request(新しいOAuthSignatureMethod_HMAC_SHA1()、$ consumer、NULL); //要求トークンを受信し、承認のために送信します。 $ parsed = OAuthUtil :: parse_parameters(file_get_contents($ req-> to_url())); $ S_REQUEST_TOK = new OAuthToken($解析済み['oauth_token']、$解析済み['oauth_token_secret']); //次の状態に進みます。 $ action = 'authorize_request_token'; 休憩; }
- 承認にリダイレクトします(ブラウザのリダイレクト経由)。 このアプリケーションには、一意のリクエストトークンがあります。 このトークンを使用するには、ユーザーから許可を取得する必要があります。 Request Tokenを許可するように彼に依頼します。
- コンシューマーは、ブラウザーを特別な認証URLプロバイダー(たとえば、 api.rutvit.ru/oauth/authorize)にリダイレクトします。 パラメータでは、リクエストトークンキーが渡されます。
- プロバイダーは、ユーザーの認証フォームを表示し、ログインしている場合はブラウザーをリダイレクトします。 正確にどこに? そして、これをoauth_callbackパラメーターで示します。
コードリスト11:承認へのリダイレクト // 3.承認(ユーザーによる確認)リダイレクトを介したトークンの要求。 //ブラウザをサービスプロバイダーにリダイレクトして、ユーザーによるアクセスを確認します。 // GETパラメータに戻ると、action = fetch_access_tokenになります。 ケース「authorize_request_token」:{ //ブラウザは確認後にこのURLに戻ります。 $ callbackUrl = "http:// {$ _SERVER ['HTTP_HOST']} {$ _SERVER ['SCRIPT_NAME']}" 。 「?action = fetch_access_token」; //パラメータでコールバックURLを渡します(OAuth 1.0プロトコル。1.0aではそうではありません!)。 $ authUrl = "http://api.rutvit.ru/oauth/authorize"。 「?」 。 「&oauth_token = {$ S_REQUEST_TOK-> key}」 。 "&oauth_callback ="。 urlencode($ callbackUrl); //ブラウザのリダイレクト。 header( "Location:$ authUrl"); exit(); }
- アクセストークンの取得(内部リクエスト)。 そのため、ブラウザは一連のリダイレクト後にアプリケーションに戻りました。 これは、プロバイダーでの認証が成功し、リクエストトークンが機能することを許可されていることを意味します。 ただし、OAuthでは、セキュリティのために、各トークンには独自の厳密に制限された目的があります。 たとえば、リクエストトークンは、ユーザーから確認を取得するためにのみ使用され、それ以外の場合には使用されません。 リソースにアクセスするには、新しいトークンを取得する必要があります-アクセストークン-または、彼らが言うように、「アクセストークンのリクエストトークンを交換する」。
- 消費者はアクセストークンURL (たとえば、 api.rutvit.ru / oauth / access_token)を参照し、 所有するリクエストトークンの代わりにアクセストークンを要求します。 リクエストは、リクエストトークンシークレットに基づいてデジタル署名されます。
- プロバイダーは、ガベージで満たされたアクセストークンを生成して返します。 また、彼の表では、アクセストークンがAPIへのアクセスを許可されていることにも注目しています。 将来APIを使用する場合、アプリケーションはアクセストークンを保持する必要があります。
コードリスト12:アクセストークンの取得 // 4.リクエストトークンをアクセストークンに交換し、アクセストークンをセッションに書き込みます。 //ユーザーによるアクセスを確認した後、リダイレクトからここに戻りました。 case 'fetch_access_token':{ $ consumer =新しいOAuthConsumer(OA_CONSUMER_KEY、OA_CONSUMER_SECRET); $ req = OAuthRequest :: from_consumer_and_token( $消費者、$ S_REQUEST_TOK、 「GET」、「http://api.rutvit.ru/oauth/access_token」、 array()//追加。 パラメータ ); $ req-> sign_request(新しいOAuthSignatureMethod_HMAC_SHA1()、$コンシューマ、$ S_REQUEST_TOK); //リクエストを実行し、アクセストークンをセッションに書き込みます。 $ parsed = OAuthUtil :: parse_parameters(file_get_contents($ req-> to_url())); $ S_ACCESS_TOK = new OAuthToken($解析済み['oauth_token']、$解析済み['oauth_token_secret']); //メッセージの送信に進みます。 $ action = 'send_msg'; 休憩; }
- API(内部リクエスト)を呼び出します。 さて、これでアクセストークンが得られ、APIメソッドを呼び出すときにそのキーを渡すことができます。
- コンシューマーは、プロバイダーAPIへの要求を生成します(たとえば、RESTイデオロギーに従ってPOST要求を使用して)。 要求では、アクセストークンキーが送信され、このトークンの共有秘密を使用して署名されます。
- プロバイダーはAPI呼び出しを処理し、データをアプリケーションに返します。
コードリスト13:APIを呼び出す // 5.メッセージを送信します。 // API URLをOAuthコンテナにラップします。 case 'send_msg':{ $ consumer =新しいOAuthConsumer(OA_CONSUMER_KEY、OA_CONSUMER_SECRET); $ req = OAuthRequest :: from_consumer_and_token( $消費者、$ S_ACCESS_TOK、 「POST」、「http://api.rutvit.ru/statuses/update.xml」、 配列( 'status' => "#"。TAG。 ""。iconv(ENCODING、 "UTF-8"、$ S_MSG)) ); $ req-> sign_request(新しいOAuthSignatureMethod_HMAC_SHA1()、$コンシューマ、$ S_ACCESS_TOK); // POSTリクエストを送信します。 $ h = curl_init(); curl_setopt($ h、CURLOPT_URL、$ req-> get_normalized_http_url()); curl_setopt($ h、CURLOPT_POST、true); curl_setopt($ h、CURLOPT_RETURNTRANSFER、true); curl_setopt($ h、CURLOPT_POSTFIELDS、$ req-> to_postdata()); $ resp = curl_exec($ h); $ code = curl_getinfo($ h、CURLINFO_HTTP_CODE); //成功した場合、ウィジェットのあるページにリダイレクトします。 if($ code!= 200){ e($応答); exit(); } header( "場所:{$ _SERVER ['SCRIPT_NAME']}"); exit(); }
スクリプトの終わり:ウィジェットの出力
スクリプトの終わりは、詳細な説明なしで明確にする必要があります。
コードリスト14:スクリプトの終わり:ウィジェットの出力 |
//終了ケース } } //利用可能なすべてのツイートを取得します。 $ text = file_get_contents( "http://api.rutvit.ru/search.xml?rpp=5&q="。urlencode( "#"。TAG)); $ TWEETS = new SimpleXMLElement($ text); //メッセージを再コーディングおよび引用して表示するショートカット。 関数e($テキスト、$引用= 1) { $ text = iconv( "utf-8"、ENCODING、$ text); エコー$引用? htmlspecialchars($テキスト):$テキスト; } ?> <スタイル> .hiddenLink {display:none} </ style> <div style = "border:1px solid black; padding:0.5em"> <?foreach($ TWEETS-> $ tweetとしてのステータス){?> <div style = "margin-bottom:6px"> <b> <?e($ tweet-> user-> screen_name)?>:</ b> <?e($ tweet-> text_formatted、0)?> </ div> <?}?> <form method = "post" action = "<?e($ _ SERVER ['SCRIPT_NAME'])?>?action = form_is_sent" style = "margin:1em 0 0 0"> <入力タイプ=「テキスト」サイズ=「30」名前=「msg」/> <入力タイプ= "送信"値= "送信" /> </ form> </ div> |
便利なOAuthリンク
- dklab.ruの現在の記事のオリジナル
- 公式OAuthウェブサイト 。
- Andy SmithによるOAuth.php
- さまざまなプログラミング言語でのOAuthプロトコルの実装 。
- OAuthの初心者向けガイド :英語のOAuthに関する記事。読むことを強くお勧めします。
- http://rutvit.ru/apps/new:Rutvit OAuthサーバーにアプリケーションを登録します。
- この記事の完全なソースコードの例。