restful_authentication

restful_authentication プラグインのメモ。検証は Rails 2.0.2 で行っています。

プラグインについて

RESTful なユーザ認証を行う事ができます。
通常のセッションを用いた認証、ベーシック認証、 Cookie による認証が利用できます。特に Cookie を用いた認証は、ブラウザを閉じた場合でも有効期間内なら有効になります(設定有効時)。

インストール

プラグインをインストールします。Rails 1.2.6 以降でないと動作しないので注意して下さい。
また、 authenticated_system.rb は RAILS_ROOT/lib 以下に展開されます。

ruby script/plugin install http://svn.techno-weenie.net/projects/plugins/restful_authentication/

追記
2008年11月現在、リポジトリが git ベースのものに移行しています。最新版を使うのであれば、以下のアドレスを確認して下さい。

git://github.com/technoweenie/restful-authentication.git

初期設定

まず、認証を行うモデルとコントローラを定義します。ここでは、デフォルトの user/sessions をそのまま使います。指定は model_name controller_name の順番で行います。

ruby script/generate authenticated user sessions

さらに、オプションとして以下が設定可能です。

--include-activation

メールを使った認証を行う事ができます。

--stateful

acts_as_state_machine というプラグインを使い、ステートフルな状態管理を行う事ができるそうです。
未検証なので、以下のアドレスをどうぞ。
http://rubyist.g.hatena.ne.jp/yamaz/20070215

--skip-migration

マイグレーションファイルが作成されなくなります。必要な値は自分で定義しないといけないので、以下のデフォルトファイルを参考に定義してください。

# RAILS_ROOT/db/migrate/xxx_create_users.rb

class CreateUsers < ActiveRecord::Migration
  def self.up
    create_table "users", :force => true do |t|
      t.column :login,                     :string
      t.column :email,                     :string
      t.column :crypted_password,          :string, :limit => 40
      t.column :salt,                      :string, :limit => 40
      t.column :created_at,                :datetime
      t.column :updated_at,                :datetime
      t.column :remember_token,            :string
      t.column :remember_token_expires_at, :datetime
      
      
    end
  end

  def self.down
    drop_table "users"
  end
end

ファイルを作成したら、 application.rb を開いて、以下を追加します。ついでに、 users/sessions_controller.rb の同様の記述はコメントアウトしておきましょう。

include AuthenticatedSystem

これが終わったら、好きなコントローラに以下のように記述します。基本的にはこれだけですべて完了です。

# 認証が必要になる
before_filter :login_required

# サブクラスなどで、認証を行いたくない場合
skip_before_filter :login_required

動作確認

以下のアドレスでチェックします。

/users/new

ユーザの作成

/sessions/new

ログイン

/sessions/destroy

ログアウト

補足

ログイン情報の取得

logged_in? 及び current_user で取得できます。

<% if logged_in? %>
  <%= current_user.login %>お姉さま、ごきげんよう。
<% end %>
Cookie の有効期限の変更

ログアウトせずにブラウザを閉じた場合、いつまでログイン状態を有効にするかの期間を変更できます。作ったモデル(ここでは User)の、以下の部分を変更します。

# RAILS_ROOT/app/models/user.rb の一部

  # These create and unset the fields required for remembering users between browser closes
  def remember_me
    remember_me_for 2.weeks
  end

なお、 cookie によるログインを有効にする場合、 RAILS_ROOT/app/views/sessions/new.html.erb を開き、書いてある指示のとおりにコメントをはずしてください。

session_path がエラーになる場合

RAILS_ROOT/app/views/sessions/new.html.erb 内に、以下の記述があります。

# RAILS_ROOT/app/views/sessions/new.html.erb の一部

<% form_tag session_path do -%>

これがエラーになる場合、 routes.rb の中を確認しましょう。

# RAILS_ROOT/config/routes.rb の一部
ActionController::Routing::Routes.draw do |map|
  map.resources :users

  map.resource :session

このように、 REST 対応用のマッピングが定義されているかどうか、確認して下さい。session_path そのものの意味については、下記のリンクが参考になると思います。

http://rails-recipebook.g.hatena.ne.jp/rrbk/20071026

User モデルの変更

User モデルに独自に定義したカラムを追加する場合、そのカラムへのアクセスには注意が必要です。RAILS_ROOT/app/models/user.rb を開いて、以下の部分を確認してください。

  # HACK HACK HACK -- how to do attr_accessible from here?
  # prevents a user from submitting a crafted form that bypasses activation
  # anything else you want your user to change should be added here.
  attr_accessible :login, :email, :name, :password, :password_confirmation

この attr_accessible がポイント。簡単に言うと、外部からはここに書いた値にしかアクセスできなくなります。なので、追加したカラムを外部から入力させるなら、ここに追加しておけば更新可能です。

ベーシック認証について

使い方がいまいち分かりません。調べたら、追記します。

蛇足

RESTful の意味について

RESTful なアプリケーションでは、サーバはクライアントの状態を管理しません。つまり、 Rails 1.0 系のようなセッションを持たないという事になります。そのため、ログイン状態を通知するためには毎回クライアントからログイン情報を送信するか、ベーシック認証等を用います。
このプラグインの場合、 ID/PASS を送信する代わりに Cookie を作成し、トークンとして利用し、ログイン/ログアウトという行為もセッション情報というリソースへの操作に置き換える事で、 RESTful な形を保っています。
このあたり、詳しく知りたい方は是非『RESTful Web サービス』を読んで下さい。というか、私もこれを読んで勉強中の身です。サンプルも Rails を使ったりしていて、とっつきやすいと思います。

RESTful Webサービス

RESTful Webサービス

なお、この Cookie について変更したい場合は、 environment.rb を編集します。

# RAILS_ROOT/config/environment.rb の一部

  config.action_controller.session = {
    :session_key => '_reinforce2_session',
    :secret      => 'xxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxxx'
  }

シークレットキーは隠しますが、このような部分が必ずあるはずです。ここで指定された値を使って、擬似的なセッションが作成されます。
Cookie の値はこのキーでハッシュされるので、ユーザによる改ざんはできない仕組み。逆に言うと、これがもれるとまずいという事です。書き換えるのは自由ですが、推測不可能な値を用いるべきでしょう。