Rails3でOmniAuthを使って認証機能

2013年3月8日

Webアプリケーションをつくるときに一番大事なのがログイン機能.最近はTwitterとかFacebookのアカウントでログインできるサイトも多くなって,これをぜひやってみたいと.RailsではOmniAuthというGemを使って簡単に実現できるらしいので,使ってみた.

参考:OmniAuthを使ってtwitter / facebookで認証する
コントローラーのメソッドをビューから呼び出す方法

基本的に参考を見ながらやったので手順はほぼ同じ.

まずはGemfileに

 gem 'omniauth'
 gem 'omniauth-twitter'
 gem 'omniauth-facebook'
 gem 'omniauth-mixi'

を追加して’bundle install’を実行.
'bundle show’でomniauthがちゃんと入ってるかどうか確認.
続いて初期化のためのファイルを’config/initializers/omniauth.rb’という名前で作成する.Mixiでも認証できるようになったらしい.
中身は

 Rails.application.config.middleware.use OmniAuth::Builder do
  provider :twitter,"Consumer key","Consumer secret"
  provider :facebook,"App ID","App Secret"
  provider :mixi, 'consumer_key', 'consumer_secret'
 end

という感じで書く.mixiは旧方式ではなく新方式(mixi Graph API)のほう.このほかにもOmniAuthではYahooとかGoogleでの認証,OpenID,GitHubとかたくさんの認証ができるらしい.詳しくはList-of-Strategiesを参照.

認証は"/auth/twitter"とか"/auth/facebook"にアクセスすると各認証ページにリダイレクトされて,認証できると戻ってくる.戻ってきたデータを扱うためにまず,ルーティングの設定をする.
match “/auth/:provider/callback" => “sessions#callback"

戻ってきたデータを処理するsessionsコントローラを作成.
$ rails g controller sessions
この中にデータを処理するcallback関数を書く.

 class SessionsController < ApplicationController
   # 認証後リダイレクトからのコールバック処理
   def callback
     auth = request.env["omniauth.auth"]
     user = User.find_by_provider_and_uid(auth["provider"], auth["uid"])
     if user
       session[:user_id] = user.id
       redirect_to "/"
     else
       User.create_with_omniauth(auth)
       redirect_to "/"
     end
   end
   # セッションの破棄
   def destroy
     reset_session
     redirect_to "/"
   end
 end

次に認証のためのuserモデルを作成.
$ rails g scaffold user provider:string uid:string name:string
今回はScaffoldを利用して一気に作成した.

userモデルにcreate_with_omniauth関数を定義する.ここでは,omniauthのリダイレクトで受け取ったデータを元にユーザのレコードを作成する.

 class User < ActiveRecord::Base
   attr_accessible :name, :provider, :uid
 
   # OmniAuthの認証データからユーザを作成
   def self.create_with_omniauth(auth)
     create! do |user|
       user.provider = auth["provider"]
       user.uid = auth["uid"]
       if user.provider == "twitter"
         user.name = auth["info"]["nickname"]
       elsif user.provider == "facebook"
         user.name = auth["info"]["name"]
       elsif user.provider == "mixi"
         user.name = auth["info"]["name"]
       end
       user.save
     end
   end
 end

最後に,認証ボタンを作成する.link_toヘルパを用いて作成できる.
topコントローラとindex関数を作成(rails g top index)して,ルートに設定(routes.rbに「root :to=>"top#index"」と追記した).

app/view/top/index.html.erbが表示されるのでここにログインボタンを作って,認証後はセッションに保存したidからユーザ名を表示.

<% if current_user %>
<%= current_user.name%>さん,ようこそ <%= link_to "Logout","/logout" %>
<% else %>
<%= link_to "Twitterでログイン", "/auth/twitter" %> <%= link_to "Facebookでログイン", "/auth/facebook" %> <%= link_to "Mixiでログイン", "/auth/mixi" %>
<% end %>

あとはrails serverでサーバを起動してlocalhost:3000を開く
ログインができたら成功.

<%= csrf_meta_tags %>

でエラーが出た時の対処
http://stackoverflow.com/questions/7281907/rails-3-1-issue-with-javascript-include-tag-in-application-html-erb

<%= stylesheet_link_tag    "application" %>
<%= javascript_include_tag "application" %>
<%= csrf_meta_tags %>

※日本語を書くときの注意
日本語(UTF-8)を使うときは"# encoding:utf-8"を書く
erbのときは<% # encoding:utf-8 %>というかんじ.
全部にいちいち書くのはめんどうなので,"app/views/layouts/application.html.erb"に書くだけでも大丈夫だった.