OAuth の Rails 実装 (oauth-plugin, oauth4r) を使ってみた
1.0 のリリース記念って訳じゃないけど、 OAuth の Rails 実装を試してみた。 ちょっと調べたところ、 OAuth の Rails 実装は2種類あるらしい。
- oauth-plugin - Google Code … Rails のプラグイン。サーバ (Provider) のジェネレータ実装のみ。ライブラリにOAuth Gemを用いている。ブログでの説明あり。
- oauth4r - Google Code … Rails のプラグイン。サーバ (Provider) とコンシューマ (Consumer) のジェネレータ実装およびサンプルあり。ライブラリにオリジナルの OAuth ライブラリを用いている。プレゼン資料による説明 (PDF)あり。
軽く両者を比較してみたところ、 oauth-plugin は機能が少ないけど使いやすそう。 oauth4r は機能は多いけど完成度はまだまだといった感じ。付属のサンプルだけなら簡単に動きそうだけどね。
今回は oauth-plugin を使ったときの記録。
インストール (Provider)
基本的に How to turn your rails site into an OAuth Provider に書かれている通りに進める。
$ sudo gem install oauth $ rails -d sqlite3 provider $ cd provider $ ./script/plugin install http://oauth-plugin.googlecode.com/svn/trunk/oauth_plugin
また、 oauth-plugin は Rails2.0 じゃないと動かない。 なので、 oauth4r に付属していた rails_rc1 ディレクトリ (Rails2.0が入ってる) をアプリの vender ディレクトリに突っ込む。 こうすれば gem でインストールした Rails (1.2.6) よりも優先して読み込んでくれる。
ユーザ管理機能の作成 (Provider)
OAuth の Provider は、 Twitter や Flickr のようにユーザのつぶやきや写真を管理する役割になる。 そのために、 Provider にユーザ管理機能を作る。 説明では acts_as_authenticated, restful_authentication, restful_openid_authentication などのプラグインを使ってねって書かれてあるけど、せっかくなので こないだ試した openid_login_generator を使うことにした。
$ ./script/generate openid_login Account $ script/generate model user openid_url:string $ rake db:migrate
ただ、 openid_login_generator は Rails2.0 ではそのまま動かなかったので、修正を加えている。
- app/controllers/account_controller.rb にて @request, @session を request, session に修正する。
- app/models/user.rb の find_first を find_by_openid_url に修正する。
Index: app/models/user.rb =================================================================== --- app/models/user.rb (revision 94) +++ app/models/user.rb (working copy) @@ -5,7 +5,7 @@ has_many :tokens, :class_name=>"OauthToken",:order=>"authorized_at desc",:include=>[:client_application] def self.get(openid_url) - find_first(["openid_url = ?", openid_url]) + find_by_openid_url(openid_url) end
これで Rails2.0 でも openid_login_generator が動くようになった。
OAuth 機能の作成 (Provider)
下準備が終わったので、いよいよ AOuth の Provider の機能を作る。 といっても、ジェネレータを呼び出すだけ。
$ script/generate oauth_provider
結構たくさんのファイルが追加される。 モデルだけでも5つある。
- app/models/client_application.rb
- app/models/oauth_token.rb
- app/models/request_token.rb
- app/models/access_token.rb
- app/models/oauth_nonce.rb
一方、コントローラは1つだけだった。
- app/controllers/oauth_controller.rb
これらのファイルは特に修正しない。 代わりに既存の User クラスを修正する。
class User < ActiveRecord::Base has_many :client_applications has_many :tokens, :class_name=>"OauthToken",:order=>"authorized_at desc",:include=>[:client_application]
ユーザと Consumer の登録 (Provider)
Web ブラウザから http://server.example.com/oauth/ にアクセスすると、ログイン画面へと転送される。
ID とパスワードを入力(今回は OpenID を使ったので OpenID のアカウント名を入力)してログインすると、 Consumer 一覧の画面が表示される。
ここで新しい Consumer を登録するようになってる。ちょっと本格的。 今回はまだ Consumer までは作らないので、内容は適当に入れる。
すると、 OAuth で使う Consumer Key と Consumer Secret が発行される。 この辺は Twitter の時と同じ。
irb から OAuth サーバにアクセスする (Consumer)
まだ Consumer 側のアプリは作っていないので、 irb を使って OAuth のトークンを取得してみる。
require 'oauth' consumer = OAuth::Consumer.new( :consumer_key => 'HeVnVSLpCpodiRZ4Pbqwlg', :consumer_secret => 'zxv4s7rM7v4bYG0PfT8MDxGUR4SidtESaQhTxBmqOk', :site => 'http://axela.machu.jp:5000', :request_token_path => '/oauth/request_token', :access_token_path => '/oauth/access_token', :authorize_path => '/oauth/authorize' )
initialize で渡す引数は、さっき OAuth の Provider で表示されてた情報になる。
req_token = consumer.get_request_token req_token.authorize_url => "http://axela.machu.jp:5000/oauth/authorize?oauth_token=BtJ18E7RgMysQ9cfc0bGDQ"
get_request_token メソッドを呼んで、 Provider から Request Token を取得する。 authorize_url メソッドで、ユーザのリダイレクト先が取得できる。
Web ブラウザでアクセスすると、 Consumer にトークンを渡してよいかどうかの確認画面が表示される。
再び irb へ戻る。 Request Token から Access Token を取得する。 以降は Access Token の GET メソッドで、 Provider 上のユーザ情報を取得する。今回はまだ Provider 上にアプリを作ってないので、データも取ってこれないけど。
access_token = req_token.get_access_token access_token.get('/photo/123456')
ここまでのまとめ
- oauth-plugin を使えば OAuth のプロバイダ側の実装は簡単に出来そう
- でも生成されるクラスが多いので、ちゃんと内容を把握しないと危険
- Consumer 側はこれから