OmniAuth と Warden を WardenOmniAuth で連携してみた

Twitter の OAuth を使って認証するのに OmniAuth を使ってみたけど、Warden と組み合わせるのが定番みたいです。

Warden と組み合わせると、ログイン成功後のユーザー情報をセッションにつめたり、ログアウトしたり、といった処理を Warden に任せられます。まぁ、ユーザー情報をデータベースに保存する場合は、その部分を書かないといけませんけどね。

Sinatra + Warden + OmniAuth + WardenOmniAuth のサンプルは次の通り。データベースは使っていません。

# coding: utf-8
require "sinatra"
require "warden"
require "omniauth"
require "omniauth-twitter"
require "warden_omniauth"

# Sinatra の有効にする
enable :sessions

# Warden の設定
Warden::Manager.serialize_into_session do |user|
  # user はハッシュなので、そのままセッションに入れる
  user
end
Warden::Manager.serialize_from_session do |user|
  # セッションから取り出した user はハッシュなので、そのまま利用する
  user
end

use Warden::Manager do |config|
  # 認証に失敗したときも Sinatra::Application を呼び出す
  config.failure_app = Sinatra::Application

  # デフォルトでは OmniAuth の Twitter 認証を使う
  config.default_strategies :omni_twitter
end

# OmniAuth の設定
use OmniAuth::Builder do
  provider :twitter, "ConsumerKey", "ConsumerSecret"
end

# WardenOmniAuth の設定
use WardenOmniAuth do |config|
  config.redirect_after_callback = "/warden/callback"
end

helpers do
  def warden
    request.env["warden"]
  end

  def current_user
    warden.user
  end
end

get "/" do
  erb :index
end

get "/warden/callback" do
  erb :home
end

get "/logout" do
  request.env["warden"].logout
  redirect "/"
end

get "/auth/failure" do
  params[:message]
end

__END__
@@layout
<!DOCTYPE html>
<html>
    <head>
        <title>Warden-OmniAuth</title>
    </head>
    <body>
        <%= yield %>
    </body>
</html>

@@index
<h1>ログイン</h1>
<a href="/auth/twitter">Twitter でログイン</a>

@@home
<h1>Wellcome</h1>
<pre>
    <%# ログインユーザーを出力する %>
    <%= current_user %>
</pre>

たまにリダイレクトループになって失敗するときあります。というか、昨日まで動かなかったのに、今日やったら上手く動くようになってました。しかも今度は全然失敗しないし。おかげで失敗した原因が調べられない…。同じ現象に遭遇した人いませんか?