Hatena::ブログ(Diary)

present このページをアンテナに追加 RSSフィード Twitter

2012-02-11

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>

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

2012-02-10

Rails3 レシピブック

まだ Rails2 が主流だったころ Rails を勉強していたんですが、Google App Engine が出たので、途中でやめて Python に移ってしまいました。それから去年までずっと Python

今年から Ruby に戻って、Rails3 に再挑戦しています。Python で Django や Kay といったフレームワーク使っていたから、Rails2 のときどこで躓いていたのかわからないくらい、Rails3 にすんなり入れました。他のフレームワークで培ったノウハウは Rails でも生かせる、というのを実感中。

足りないのは「Rails3 ではメールどうやればいいんだっけ」「Rails3 ではリレーションどうすればいいんだっけ」といった、Rails3 でのやり方くらいです。そこで本書のようなレシピブックの出番。

Google 先生に聞くのもいいですけど、やっぱり手元にあった方が調べるのに早いです。本書は Rails 入門レベルのレシピからだんだん高度になっていくので、Rails 入門したてでもなんとか読み進めていける内容だと思います。

Rails 初挑戦でいきなり本書だけ、っていうのはさすがにキツイと思いますが、既に他の言語でフレームワークに慣れ親しんでいる人なら、Rails の勉強はレシピブックとネットの情報で足りるんじゃないでしょうか。私の場合は、今のところ何とかなっています。

Rails3レシピブック 190の技
高橋 征義 松田 明 諸橋 恭介
ソフトバンククリエイティブ
売り上げランキング: 60469

2012-02-08

Ruby でベンチマーク計測

Javaサーブレットコンテナ、まぁ Jetty なんですけど、Jetty の HTTP サーバーとしての性能がどれくらいか分かる資料が無かったので、Rubyベンチマークを計測するスクリプトを書いてみました。ついでにサーブレットも計測しています。benchmark モジュール初挑戦。

# coding: utf-8
require "open-uri"
require "benchmark"

HTML_URL = "http://192.168.56.101:8080/helloworld/"
SERVLET_URL = HTML_URL + "hello"

# ベンチマーク対象のメソッド
def open_service(uri)
  # 指定した URI にアクセスしてレスポンスを取得するだけ
  open uri do |s|
    s.read
  end
end

# 渡したブロックを 1, 10, 100, 1000 回繰り返すのにかかる時間を計測
def do_benchmark(caption, &block)
  Benchmark.benchmark(caption + Benchmark::CAPTION,
                      7,
                      Benchmark::FMTSTR) do |r|
    [1, 10, 100, 1000].each do |n|
      # block を n 回繰り返したときのベンチマーク
      r.report n.to_s do
        n.times &block
      end
    end
  end
end

# 静的ファイルにアクセス
do_benchmark("static  ") do
  open_service(HTML_URL)
end
puts

# サーブレットにアクセス
do_benchmark("servlet") do
  open_service(SERVLET_URL)
end

このスクリプトを実行した結果は次の通り。


C:\work>ruby benchmark_jetty.rb
static        user     system      total        real
1        0.078000   0.312000   0.390000 (  0.419042)
10       0.016000   0.000000   0.016000 (  0.128013)
100      0.156000   0.078000   0.234000 (  1.221122)
1000     0.764000   1.560000   2.324000 ( 12.743274)

servlet      user     system      total        real
1        0.000000   0.000000   0.000000 (  0.014002)
10       0.000000   0.016000   0.016000 (  0.134013)
100      0.063000   0.156000   0.219000 (  1.281129)
1000     1.451000   0.670000   2.121000 ( 13.073307)

このスクリプトで計測したデータが、実際に役に立つかどうかは微妙ですけどね。ていうか、たぶん JMeter あたりを使って計測し直すこと間違いなし。

2012-02-06

Sequel でマイグレーション

Sequel にはマイグレーション機能があるので、Rails と同じようにテーブルの作成やスキーマ変更ができます。

サンプル程度ならアプリケーションのファイルに create_table べた書きでいいけど、ちゃんとしたサービス作るときはマイグレーションを使ったほうが良いですよね。

マイグレーションファイルの名前は、最初に通し番号またはタイムスタンプを付けて、APP_ROOT/db/migrate ディレクトリに配置するのが慣習。

001_create_users.rb
Sequel.migration do
  up do
    create_table :users do
      primary_key   :id
      String        :name, :null => false
      String        :password, :null => false
      DateTime      :created_at
    end
  end

  down do
    drop_table :users
  end
end

あとは APP_ROOT で次のコマンドを実行。

sequel -m ./db/migrate sqlite://sample.db

たったこれだけ。簡単ですね。sqlite://〜 の部分は、使っているデータベースに合わせて修正してください。

2012-02-03

Sinatra + OmniAuth で Twitter の OAuth を試してみた

Sinatra アプリの認証に Warden を使おうとしてたけど、「ユーザー名とパスワードを自前で保存したくない」と思い直して、OAuth や OpenID を検討し始めました。TwitterFacebook や GitHub など、いろんな OAuth に対応したいから、使うライブラリは OmniAuth かな。

Sinatra + OmniAuth で、Twitter の OAuth を使って認証するサンプルを書いてみました。

# coding: utf-8
require "sinatra"
require "omniauth"
require "omniauth-twitter" # Twitter の OAuth を使うなら必須

# Sinatra のセッションを有効にする
enable :sessions

# OmniAuth の設定
use OmniAuth::Builder do
  # Twitter の OAuth を使う
  provider :twitter, "Consumer key", "Consumer secret"
end

get "/" do
  erb :index
end

# Twitter の認証が成功したら呼び出される
get "/auth/:provider/callback" do
  # 認証情報は request.env に格納されている
  @auth = request.env["omniauth.auth"]
  erb :home
end

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

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

@@home
<h1>Wellcome</h1>
<pre>
    <%= @auth %>
</pre>

たったこれだけのコードで実装できてしまった…。以前、Python + AppEngine + Kay Framework で Twitter の OAuth に挑戦したときは、結構コード書いたのにな。