Sinatraで書いているwebアプリに認証機能が必要になったので「sinatra-authentication」を使ってみたメモ。

概要

Rubyでwebアプリを書くのに大人気のSinatra。でもweb開発で必要になる機能ってどんなフレームワークでもあんまり変わらないので、そのうち「認証機能が必要だよね」なんてことになる。

最初はRack::Auth::Basicを使っていたのだが、ユーザの追加 / 変更が面倒だったり、どうも挙動が不安定だったり(一定時間ログインできなくなるという謎の不具合が出たり)したので、他のライブラリを検討してみた。

自分でこんな感じのものを作ろうかなーとも思ったのだが、まずはあるものを使ってみよう、ということで「sinatra-authentication」を導入してみた。

環境

  • CentOS 5.4
  • MySQL 5.1.47
  • apache 2.2.14
  • ruby 1.9.1 p378
  • rack 1.2.1
  • passenger 2.2.14
  • sequel 3.13.0
  • ruby-mysql 2.8.1
  • sinatra 1.0
  • sinatra-authentication HEAD (0.3.2 159149)
  • rack-flash 0.1.1
  • haml 3.0.16

ポイント

  • SinatraのアプリケーションクラスはSinatra::Baseを継承する「Modularスタイル」を使おう。
  • sinatra-authenticationはtrunkの先端を持ってきている。sequel対応したものはまだgem化されていない(2010-08-10現在)。ドキュメントやサンプルがないのでちょっと手探りが必要だった。
  • use Rack::Flashはセッション開始後に記述する。
  • Sequel::Modelは利用時にSequel.connectでDB接続が要求される。
  • 拡張モジュールを使うにはクラス定数をregisterする。
  • lib/models/sequel_user.rbに認証用テーブルのmigrationが書いてあるのだが、MySQLではこのまま通らない。:unique => trueなのでUnique Indexが作成されるのだが、MySQLではTEXT型につけるindexに長さを指定する必要がある。Sequelでの指定方法が見つからなかったので、とりあえず定義を書き換えてしのいでいる。あらかじめtableを作成しておいてもok。
  • extended_views/signup.hamlには使われていない「user_name」というinputが定義されている。これがあるとSequelがsaveに失敗する(カラムがないから当然)ので、フィールドを削除しよう。
  • その他細かい解説はソースコードにコメントしておいた。

ソースコード

sinatra-authentication / lib / models / sequel_user.rb

#    String :email, :unique => true, :text => true
String :email, :unique => true, :size => 255 # こっち

app.rb

# -*- encoding: utf-8 -*-
require 'sequel'
require 'sinatra/base'
require 'haml'
# Sequel::Modelは呼び出し時にDB接続を要求する。
# lib/sequel_user.rbでDBを要求するので、接続してからrequireする必要がある。
DB = Sequel.connect "mysql:://#{username}:#{password}@#{host}/#{database}"
require 'sinatra-authentication'
require 'rack-flash'
class MyModule::MyApp < Sinatra::Base
  register Sinatra::SinatraAuthentication # 拡張モジュールとしてSinatraAuthenticationを使用するよ
  # sinatraお決まりの設定
  set :public, File.join('path', 'to', 'public')
  set :views,  File.join('path', 'to', 'views')
  # sinatra-authentication付属のテンプレートを置いたパスを指定
  set :sinatra_authentication_view_path, File.join('path', 'to', 'views', 'extend_views/')
  # セッションの寿命と暗号化キーを指定
  use Rack::Session::Cookie, :expire_after => 3600, :secret => 'change_me'
  # Rack::Flashの使用宣言 / use Rack::Session のあとに記述すること
  use Rack::Flash
  get '/' do
    login_required              # 認証が必要なルート -> 失敗するとログインフォームへ
    haml :index                 # 認証が通ればこっち
  end
end

config.ru

# -*- coding: utf-8 -*-
require ::File.join 'path', 'to', 'app'
use MyModule::MyApp
run Sinatra::Base

まとめ

sequelへの対応がわりと最近されたので、まだ全然落ち着いていない感じのライブラリであるが、ハマりポイントさえ押さえておけば手早く認証機能が作れて、簡単な権限管理までついてくる。IDはメールアドレスを想定してバリデートしちゃうとか、facebook対応がついてきちゃうとか、いろいろツッコミどころはあるが、試してみてはいかがだろうか。