久しぶりのブログ更新です。仕事の方はひたすらJavaなのですが、サンデープログラミングの方はRuby&JavaScriptに戻ってきました。やっぱりRubyいいです。本当にプログラミングしてて楽で速い。特に読むのも書くのも短いのがいいです。JavaはIDEのお陰で書くのは速いですが、読むのが時間がかかります。
今日の実装は、最近増えてきたTwitterのアカウントで自分のWebサービスを使ってもらう、いわゆる”Sign in with Twitter”の実装例です。詳しいOAuthの仕組みは、
https://dev.twitter.com/docs/auth/sign-in-with-twitter
をご覧頂くのが良いと思います。最近これで認証するサービスが多いので、感覚で知っている方も多いのではないでしょうか。
なお、参考にさせて頂いたのは、
Sinatra と OAuth を使って Twitter のタイムラインを取得してみた
http://www.machu.jp/diary/20090818.html#p01
この記事になります。ちょっと古かったので、sinatraやtwitterの書き方を替えたり、テンプレートをhamlに変更させてもらいました。Herokuでずっと動くようにGemfileも作ってライブラリのバージョンを固定してあります。
実装してHerokuにアップロードしたサンプルは、
Sample of sign in with Twitter
http://twitter-login.heroku.com/
となります。tiwtterでログインボタンがありますので、ログイン、認証してもらうと、認証したアカウントのタイムラインが表示されます。一応ログアウトもできます。
ソースは、
Github sifue / twitter_login
https://github.com/sifue/twitter_login
においておきましたので、基本的にはここからダウンロードして、twitter_login.rbの冒頭にある、
KEY = "your_consumer_key" SECRET = "your_consumer_secret"
ここを、https://dev.twitter.com/appsで登録した自分のアプリケーションのものに書き換え、gitのリポジトリが設定してある状況で以下のようにHerokuにpushし、動かすことができます。
$ git push heroku master
というわけで、ぜひHeroku上でサンプルを動かしてみてください。
なお、ローカルにコピーして、ruby 1.9.2とrubygemのある環境でこのフォルダに移動して
$ gem install bundler $ bundle install $ ruby -rubygems twitter_login.rb
と実行しても http://localhost:4567/ で動くと思います。gem installは状況によってはsudoがいるかもしれません。
というわけでソースの解説。メインの
twitter_login.rb
require 'sinatra' require 'haml' require 'oauth' require 'twitter' set :haml, {:format => :html5 } helpers do include Rack::Utils alias_method :h, :escape_html end configure do use Rack::Session::Cookie, :secret => Digest::SHA1.hexdigest(rand.to_s) KEY = "your_consumer_key" SECRET = "your_consumer_secret" end before do if session[:access_token] Twitter.configure do |config| config.consumer_key = KEY config.consumer_secret = SECRET config.oauth_token = session[:access_token] config.oauth_token_secret = session[:access_token_secret] end @twitter = Twitter::Client.new else @twitter = nil end end def base_url default_port = (request.scheme == "http") ? 80 : 443 port = (request.port == default_port) ? "" : ":#{request.port.to_s}" "#{request.scheme}://#{request.host}#{port}" end def oauth_consumer OAuth::Consumer.new(KEY, SECRET, :site => "http://twitter.com") end get '/' do @title = 'Sample of sign in with Twitter' haml :index end get '/logout' do @twitter = nil session.clear redirect '/' end get '/request_token' do callback_url = "#{base_url}/access_token" request_token = oauth_consumer.get_request_token(:oauth_callback => callback_url) session[:request_token] = request_token.token session[:request_token_secret] = request_token.secret redirect request_token.authorize_url end get '/access_token' do request_token = OAuth::RequestToken.new( oauth_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]) session[:access_token] = @access_token.token session[:access_token_secret] = @access_token.secret redirect '/' end
次にindexのテンプレートの
views/index.haml
!!! XML !!! %html %head %meta{ 'http-equiv' => 'content', :content => 'text/html; charset=utf-8'} %title= @title %body %div#container %h1= @title - if not @twitter %a(title='OAuth Login' href='/request_token') %img(src='sign-in-with-twitter-l.png') - if @twitter %a(title='logout' href='/logout')Logout %h3= 'Login now! Show your home_timeline' %hr/ - @twitter.home_timeline.each do |status| %p= status.user.name %p= status.text %hr/
動きとしては、ルートにアクセスしたらindex.hamlを表示。ページの中にあるログインボタンを押すと/request_tokenでアクセページを取得してリダイレクト、そのあと認証のトークン類が戻ってきたらセッションに結果を入れて再度ルートページに戻すという形です。
ルートのindex.hamlはtwitterのクライアントインスタンスがあるかどうかで動きを変えています。
これをJavaで書くとあっさり1000行とかいっちゃうのかなと思います。xmlだけでも結構な量になりそうです。
なお
config.ru
require './twitter_login' run Sinatra::Application
及び
Gemfile
# Detail http://devcenter.heroku.com/articles/bundler source 'http://rubygems.org' gem 'sinatra' , '1.3.1' gem 'haml' , '3.1.3' gem 'oauth' , '0.4.5' gem 'twitter' , '1.7.2'
これはHerokuで動かしたり、Bundlerで簡単にライブラリ環境を整えるための設定になります。
Sinatraといいhamlといい、やっぱりRubyには先進的な試みがいっぱい実装されてるなぁと今日この頃。いろいろ勉強になります。