OAuthが前々から気になっていたので、RailsでTwitterのOAuthを使うサンプルを作成しました。OAuthについてはここでは詳しく説明しませんが、
の記事がよくまとまっているので、目を通してみるとよいでしょう。OAuthを一言でいうと、サードパーティのアプリケーション(Consumer)をサービスプロバイダ側(Service Provider)で認可するという仕組みで、端的に言えばサードパーティ側でサービスプロバイダのアカウント情報を保持する必要がなくなるというメリットがあります。
たとえば、今回の例だとTwitter(=Service Provider)のデータを利用するので、Twitterから認可を受ける必要があります。これをOAuthという仕組みを使って、サンプルアプリケーション(=Consumer)ではTwitterのアカウント情報を一切入力させないようにします。
Twitter API WikiにOAuth Example - Rubyという素晴らしいページがあるのですが、これが最新版の仕様に対応してなさそうなので、上げてみました。
railsやoauthなどのライブラリのインストール
必要なものは以下になるので、rubygemsでインストールしておきます。
- rails 2.3.2
- oauth 0.3.5
$ sudo gem install rails
$ sudo gem install oauth
$ sudo gem install json
Twitterでアプリケーションを登録
サンプルを作る前にTwitterのOAuthのページでアプリケーションを登録します。
Callback URLは http://localhost:3000/oauth_callback とか書くとエラーになるので、http://example.com/ のように適当なURLを記載しておきます。(実際にここで設定したURLがコールバックされるわけではありません)
全て記入して登録すると、Consumer keyとConsumer secretが発行されるのでこれを記録しておきます。後述する IndexController でこれらを使用します。
サンプル作成
サンプルアプリの雛形を作成します。
$ rails twitoauth
$ cd twitoauth
$ script/generate controller index
IndexControllerの作成
app/controllers/index_controller.rbを編集して、IndexControllerを実装します。Consumer key、Consumer secretは先ほどTwitterから発行されたものを使用してください。
require 'oauth'
require 'json'
class IndexController < ApplicationController
def self.consumer
OAuth::Consumer.new(
"Consumer key",
"Consumer secret",
{ :site => "http://twitter.com" }
)
end
def index
end
def oauth
# :oauth_callbackに認証後のコールバックURLを指定
# この場合だとこのコントローラー内の oauth_callback メソッドが実行される
request_token = IndexController.consumer.get_request_token(
:oauth_callback => "http://#{request.host_with_port}/oauth_callback"
)
session[:request_token] = request_token.token
session[:request_token_secret] = request_token.secret
# twitter.comで認証する
redirect_to request_token.authorize_url
return
end
def oauth_callback
consumer = IndexController.consumer
request_token = OAuth::RequestToken.new(
consumer,
session[:request_token],
session[:request_token_secret]
)
access_token = request_token.get_access_token(
{},
:oauth_token => params[:oauth_token],
:oauth_verifier => params[:oauth_verifier]
)
response = consumer.request(
:get,
'/account/verify_credentials.json',
access_token, { :scheme => :query_string }
)
case response
when Net::HTTPSuccess
@user_info = JSON.parse(response.body)
unless @user_info['screen_name']
flash[:notice] = "Authentication failed"
redirect_to :action => :index
return
end
else
RAILS_DEFAULT_LOGGER.error "Failed to get user info via OAuth"
flash[:notice] = "Authentication failed"
redirect_to :action => :index
return
end
end
end
完了したら、indexアクションに対応するViewである app/views/index/index.erb を作成します。これは単純に /oauth に飛ばすだけのテンプレートです。
OAuthのサンプル
config/routes.rb を修正
次に IndexController に定義されているアクションが呼び出されるようにURLとのマッピングをします。具体的には config/routes.rb の
map.connect ':controller/:action/:id'
map.connect ':controller/:action/:id.:format'
となっている箇所の上に下記を追記します。
map.root :controller => 'index'
map.connect ':action', :controller => 'index'
OAuthを試してみる
とりあえず9割方準備が整ったので、サーバを起動して http://localhost:3000/ にアクセスします。
$ script/server
OAuthで認証のリンクをクリックすると、下記のようにTwitterにリダイレクトされたでしょうか?(うまくリダイレクトされない場合は index_controller.rb の index アクションのコードに問題がある可能性が高いです)
ここでTwitterのアカウントを入力して"Allow"をクリックすると、「アプリに転送します」というメッセージが表示され、サンプルアプリに遷移します。具体的には、index_controller.rb のoauthアクション内のget_request_tokenメソッドで登録したコールバックURLにリダイレクトされています。
ただ、現状だとコールバック先の画面で使用するテンプレートファイルを作成していないため
Template is missing
Missing template index/oauth_callback.erb in view path app/views
というエラーになるので、次はこのテンプレートを作成します。
最後の仕上げ
/oauth_callback のテンプレートを下記の内容で作成します。やっていることは単純で、/account/verify_credentials.json のAPIで取得した情報を表示しているだけです。
TwitterからOAuthで認証してもらったよ!
<%= @user_info['name'] %>さんの最新のつぶやき
<%= @user_info['status']['text'] %>
これを app/views/oauth_callback.rb として保存したら、もう一度 http://localhost:3000/ にアクセスして最初から認証をやり直します。下記のようにTwitterの情報が取得できれば、OAuthでの認証+APIの呼び出しは成功です。
まとめ
ライブラリを使えば少しの労力でOAuthでTwitterに認証してもらえることが伝わったでしょうか?OAuthを使えば、サービス側(Consumer側)でTwitterのアカウント/パスワードを保持しなくて済むので、よりユーザに安心を提供できるはずです。現状、コールバックURLを使う方法はPCのブラウザでしか実行できませんが、モバイルやデスクトップアプリのためにPINコードを発行する方法も用意されているので、より詳しく知りたい人は本家のドキュメントを読んでみると良いと思います。