at posts/single.html

OAuth の Rails 実装 (oauth-plugin, oauth4r) を使ってみた

1.0 のリリース記念って訳じゃないけど、 OAuth の Rails 実装を試してみた。 ちょっと調べたところ、 OAuth の Rails 実装は2種類あるらしい。

軽く両者を比較してみたところ、 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/ にアクセスすると、ログイン画面へと転送される。

OAuth Sample (1)

ID とパスワードを入力(今回は OpenID を使ったので OpenID のアカウント名を入力)してログインすると、 Consumer 一覧の画面が表示される。

OAuth Sample (2)

ここで新しい Consumer を登録するようになってる。ちょっと本格的。 今回はまだ Consumer までは作らないので、内容は適当に入れる。

OAuth Sample (3)

すると、 OAuth で使う Consumer Key と Consumer Secret が発行される。 この辺は Twitter の時と同じ。

OAuth Sample (4)

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 にトークンを渡してよいかどうかの確認画面が表示される。

OAuth Sample (5)

再び 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 側はこれから

関連する日記