ログイン機能は当然ながら、Webサービスで必須の機能の1つです。しかし、自前で認証機能を持つと面倒だったり、ユーザに対して壁を与えてしまう場合があるかもしれません。そんな時は、omniauthを使ってTwitter, Facebook認証を実装すると良いと思います。いわゆる「Twitterでログイン」ボタンみたいなやつです。
omniauthによって、例えばTwitterで認証を行いたいときは、http://yourapp.com/auth/twittterにリンクすればtwitter認証ページに飛び、認証が成功すればhttp://yourapp.com/auth/twitter/callbackがコールバックされます。規約の力ってすごいですね!
尚、対象とするRailsのバージョンは3です。
1. omniauthのインストール
Gemfileの末尾に、
gem "omniauth"
と記述して、
bundle install
するだけです。Rails3になってから大変便利になりました。
2. omniauthの設定
Twitter及びFacebookのアプリケーション登録画面で作成しているアプリケーションを登録します。
Sign in with your Twitter account | Twitter Developers
Facebook
アプリケーションの名前や詳細は適当で構いませんが、
TwitterのCallback URL | http://localhost:3000/auth/twitter/callback |
FacebookのサイトURL | http://localhost:3000/ |
にしておきます。本番環境とかでは、当然ながら適宜変更します。どちらも、アプリの作成が済むと、
Consumer Key, Consumer Secret | |
App ID, App Secret |
の値が手に入ると思います。これはとても大切なので控えておいてください。ちなみに私はEvernoteに取り込んでしまっています。そしたら、Railsアプリケーションに戻って、initializers/omniauth.rbというファイルを作成し、以下を書き込みます。
Rails.application.config.middleware.use OmniAuth::Builder do provider :twitter, 'CONSUMER_KEY', 'CONSUMER_SECRET' provider :facebook, 'App ID', 'App Secret', {:client_options => {:ssl => {:ca_path => "/etc/ssl/certs"}}} end
これでomniauthの設定は終了です。なんかFacebookだと、SSL証明書の位置を明示しなければいけないみたいです...
ruby on rails - OmniAuth & Facebook: certificate verify failed - Stack Overflow
3. Model, Controllerの作成と設定
まずUserモデルを作成します。Twitterだと返却値の中にメールアドレスが無いので、ユーザに入力して貰う必要があります。今回は本当に最低限ということで放置します...
rails g model user nickname:string email:string image_url:string rake db:migrate
これで、userテーブルとそれを取り扱うためのUserモデルが作成されてしまいました。速い!
次に、ログイン処理を扱うsessionsコントローラを作成します。ついでに、サイトのトップになるwelcomeコントローラとindexアクションも作成しておきます。
rails g controller welcome index rails g controller sessions
ここでルーティングを決めておきます。config/routes.rbに以下を記述します。
root :to => 'welcome#index' # for omniauth settings match 'auth/:provider/callback' => 'sessions#login' match '/logout' => 'sessions#logout', :as => :logout
アプリケーションのルートにアクセスしたらwelcome#indexが呼び出されるようにし、またコールバックされたら、sessions#loginが処理を担当します。あと、ログアウト機能はsessions#logoutが担当します。
上で担当アクションを決めたので、処理を実装してしまいます。app/controllers/sessions_controller.rbに以下を記述します。
def login auth = request.env['omniauth.auth'] user = User.find_by_nickname(auth['user_info']['nickname']) || User.create_account(auth) session[:user_id] = user.id logger.debug auth.to_yaml redirect_to root_url, :notice => 'ログインしました。' end def logout session[:user_id] = nil redirect_to root_url, :notice => 'ログアウトしました。' end
返却値のハッシュをauth変数が受け取り、次に認証したユーザが既に登録しているユーザかを確認しています。まだ未登録のユーザであれば、Userクラスのクラスメソッドcreate_accountを用意し、ユーザ登録処理をここに実装するようにします。本来は、新規登録フォームでユーザに色々情報を登録してもらうという流れになるかと思います。
早速、create_accountメソットを以下の通り実装してしまいましょう。
def self.create_account(auth) user = User.new user.nickname = auth['user_info']['nickname'] user.email = auth['user_info']['email'] user.image_url = auth['user_info']['image'] user.save! end
幸いにも、TwitterとFacebookの返却値が似通っているのでコードが少なくて住みました。saveメソッドですが、「!」を付けないと返り値がtrue/falseになりますが、付けるととuserオブジェクトか例外になるようです。
4. View開発
最後にログイン・ログアウトリンクを実装してします。ログイン処理は、ページ全体の共通の処理なので、レイアウトファイルに記述します。app/views/layouts/application.html.erbのbodyの直下あたりに以下を記述します。
<% if current_user -%> ようこそ、<%= current_user.nickname %>さん。 | <%= link_to 'logout', logout_path %> <% else -%> <%= link_to 'Twitterでログイン', 'auth/twitter' %> <%= link_to 'Facebookでログイン', 'auth/facebook' %> <% end -%>
ここで、current_userというメソッドを自作しています。view内に長ったらしいrubyのコードがあると、見通しが悪くなってしまう為です。そのためにRailsはviewヘルパーを用意してくれています。今回、ログインユーザがいればuserオブジェクトを返せば良いので、app/helpers/application_helper.rbに
def current_user @current_user ||= User.find(session[:user_id]) if session[:user_id] end
と記述します。
5. デモ!
さて、確認してみます。まずサーバを起動してhttp://localhost:3000/にアクセスすると、以下のようなページが出現します。
そして、TwitterやFacebookでログインボタンを押すと、それぞれ以下のようなページが出現して、そちら側で認証を要求されます。
そして、ログインすると、以下のように表示されます。
上出来ですね!個人のWebサービス、どんどん盛り上げていきたいものです。もしも動かないとかご意見があればコメントでもTwitterでもお問い合わせください!