ホーム > Rails > RailsでTwitterのOAuthを試す

RailsでTwitterのOAuthを試す

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
  • json
$ sudo gem install rails
$ sudo gem install oauth
$ sudo gem install json

Twitterでアプリケーションを登録

サンプルを作る前にTwitterのOAuthのページでアプリケーションを登録します。

Twitterでアプリケーションを登録

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 に飛ばすだけのテンプレートです。

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>OAuthのサンプル</title>
</head>
<body>
<a href="/oauth">OAuthで認証</a>
</body>
</html>

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でOAuth認証

ここで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で取得した情報を表示しているだけです。

<html>
<head>
<meta http-equiv="content-type" content="text/html; charset=utf-8" />
<title>TwitterからOAuthで認証してもらったよ!</title>
</head>
<body>
<h1><%= @user_info['name'] %>さんの最新のつぶやき</h1>
<%= @user_info['status']['text'] %>
</body>
</html>

これを app/views/oauth_callback.rb として保存したら、もう一度 http://localhost:3000/ にアクセスして最初から認証をやり直します。下記のようにTwitterの情報が取得できれば、OAuthでの認証+APIの呼び出しは成功です。

OAuthでログインしてTwitterのデータを取得

まとめ

ライブラリを使えば少しの労力でOAuthでTwitterに認証してもらえることが伝わったでしょうか?OAuthを使えば、サービス側(Consumer側)でTwitterのアカウント/パスワードを保持しなくて済むので、よりユーザに安心を提供できるはずです。現状、コールバックURLを使う方法はPCのブラウザでしか実行できませんが、モバイルやデスクトップアプリのためにPINコードを発行する方法も用意されているので、より詳しく知りたい人は本家のドキュメントを読んでみると良いと思います。

RailsによるアジャイルWebアプリケーション開発

著者/訳者:Sam Ruby David Heinemeier Hansson Dave Thomas

出版社:オーム社( 2009-12 )

単行本 ( 675 ページ )



こちらもあわせてどうぞ


カテゴリー: Rails タグ: , ,
  1. kojiro
    2010 年 3 月 19 日 12:51 | #1

    はじめまして。kojiroと申します。
    いきなりぶしつけに申し訳ございませんが、ご教授頂きたく思います。

    【RailsでTwitterのOAuthを試す】を試してみたのですが、OAuthで認証を押した段階でtwitterの画面に遷移せず、以下のようなエラーが表示されてしまいます。

    OAuth::Unauthorized in IndexController#oauth
    401 Unauthorized
    C:/ruby/lib/ruby/gems/1.8/gems/oauth-0.3.6/lib/oauth/consumer.rb:200:in `token_request’
    C:/ruby/lib/ruby/gems/1.8/gems/oauth-0.3.6/lib/oauth/consumer.rb:128:in `get_request_token’
    C:/ruby/twitoauth/app/controllers/index_controller.rb:19:in `oauth’

    変更したのは self.consumer メソッドの”Consumer key”,”Consumer secret”を自分で取得したtwitterアプリのものに変えたくらいです。あとは変更していません。

    環境はWindowsを使っております。
    gem oauthが現在0.3.6になっていたので0.3.5にしてみましたがやはり同じでした。

    お手数をおかけします。よろしくお願いいたします。

  2. 2010 年 3 月 20 日 07:19 | #2

    @kojiro さん

    自分の環境ではそのままのコードで動きました。OAuthで認証してもらう時のHTTP Headerを調べてみると何かヒントがあるかもしれません。

  3. kojiro
    2010 年 3 月 25 日 01:03 | #3

    kojiroです。
    回答して頂きありがとうございました。
    また、報告が遅くなってしまって申し訳ございません。
    今回に関してですが、解決いたしました。
    登録していたアプリが何故かTwitter側で弾かれていたようです。
    新しいアプリを登録し直して試したところ出来ました。
    別にbotやSpamに使ったわけでもなく、通知も無かったので全く気にしていなかった部分でした・・・。

  4. Andy
    2010 年 5 月 6 日 00:24 | #4

    はじめまして。
    参考にさせていただいています。試してみたところ,get_access_tokenの中で
    comparison of String with OAuth::RequestToken failed
    となってしまいます。
    他のサイトを見ると,get_access_tokenのパラメータを単純に
    :oauth_verifier => params[:oauth_verifier]
    だけにしている例が多いようなので,そうしてみると
    401 Unauthorized
    のエラーになります。OAuth gemのバージョンは0.4.0です。
    何かわかりますでしょうか?

  5. Andy
    2010 年 5 月 6 日 01:37 | #5

    自己解決しました。session[:request_token] = request_token.token
    の「.token」が抜けていました。

  6. 2010 年 5 月 6 日 10:09 | #6

    @Andy さん
    自己解決されたとのことで良かったです。エラーメッセージだけ見ただけではなかなかわかりにくそうですね…

  1. 2010 年 5 月 23 日 22:50 | #1