Hatena::ブログ(Diary)

Run on Rails このページをアンテナに追加 RSSフィード

2008-06-22

open_id_authenticationプラグインを使う

いますぐ使えるOpenID:特集|gihyo.jp … 技術評論社

第4回 Railsで作るOpenID対応アプリケーション実践(前編):いますぐ使えるOpenID|gihyo.jp … 技術評論社


まちゅダイアリーや上記連載など大変役に立っているのですが、これはいけません。コードの断片しか掲載されていないじゃないですか。これじゃあ僕レベルの者には動くものは作れません。苦労しました。


なんとか動かすことができたのでメモを残しておく。

環境

※Ruby OpenID Libraryのインストールについては「Ruby OpenID Libraryに付属しているRP、OPのサンプルを動かしてみる - Run on Rails」を参照。


open_id_authenticationプラグインのインストール

任意の名前でアプリを作る。ここではopenid_testとする。僕はPostgreSQLを使っているのでデータベースの指定も忘れずに。

$ rails --database=postgresql openid_test
$ cd openid_test

config/database.ymlを環境に合わせて調整。データベースを作成しておく。

$ vi config/database.yml
$ createdb openid_test_development

下準備は整ったので、openid_authenticationプラグインのインストールを行う。

$ script/plugin install open_id_authentication
+ ./CHANGELOG
+ ./README
+ ./Rakefile
+ ./generators/open_id_authentication_tables/open_id_authentication_tables_generator.rb
+ ./generators/open_id_authentication_tables/templates/migration.rb
+ ./generators/upgrade_open_id_authentication_tables/templates/migration.rb
+ ./generators/upgrade_open_id_authentication_tables/upgrade_open_id_authentication_tables_generator.rb
+ ./init.rb
+ ./lib/open_id_authentication/association.rb
+ ./lib/open_id_authentication/db_store.rb
+ ./lib/open_id_authentication/nonce.rb
+ ./lib/open_id_authentication.rb
+ ./tasks/open_id_authentication_tasks.rake
+ ./test/normalize_test.rb
+ ./test/open_id_authentication_test.rb
+ ./test/status_test.rb
+ ./test/test_helper.rb

README(vendor/plugins/open_id_authentication/README)はちゃんと読むこと。このエントリーの内容も基本的にはREADMEをもとにしている。

READMEに従って以下の手順を実施。

$ rake open_id_authentication:db:create
(in /home/tokusima/openid_test)
      create  db/migrate
      create  db/migrate/20080622092350_add_open_id_authentication_tables.rb
$ rake db:migrate
(in /home/tokusima/openid_test)
== 20080622092350 AddOpenIdAuthenticationTables: migrating ====================
-- create_table(:open_id_authentication_associations, {:force=>true})
   -> 0.2502s
-- create_table(:open_id_authentication_nonces, {:force=>true})
   -> 0.2685s
== 20080622092350 AddOpenIdAuthenticationTables: migrated (0.5194s) ===========


マイグレーションファイルをみておこう。正直なところ2系になって細部は理解できていないのだけど先に進む。

$ cat db/migrate/20080622092350_add_open_id_authentication_tables.rb
class AddOpenIdAuthenticationTables < ActiveRecord::Migration
  def self.up
    create_table :open_id_authentication_associations, :force => true do |t|
      t.integer :issued, :lifetime
      t.string :handle, :assoc_type
      t.binary :server_url, :secret
    end

    create_table :open_id_authentication_nonces, :force => true do |t|
      t.integer :timestamp, :null => false
      t.string :server_url, :null => true
      t.string :salt, :null => false
    end
  end

  def self.down
    drop_table :open_id_authentication_associations
    drop_table :open_id_authentication_nonces
  end
end

テーブル構造もみておく。

openid_test_development=# \d
                             List of relations
 Schema |                    Name                    |   Type   |  Owner
--------+--------------------------------------------+----------+----------
 public | open_id_authentication_associations        | table    | tokusima
 public | open_id_authentication_associations_id_seq | sequence | tokusima
 public | open_id_authentication_nonces              | table    | tokusima
 public | open_id_authentication_nonces_id_seq       | sequence | tokusima
 public | schema_migrations                          | table    | tokusima
(5 rows)

openid_test_development=# \d open_id_authentication_associations
                                   Table "public.open_id_authentication_associations"
   Column   |          Type          |                                    Modifiers
------------+------------------------+----------------------------------------------------------------------------------
 id         | integer                | not null default nextval('open_id_authentication_associations_id_seq'::regclass)
 issued     | integer                |
 lifetime   | integer                |
 handle     | character varying(255) | default NULL::character varying
 assoc_type | character varying(255) | default NULL::character varying
 server_url | bytea                  |
 secret     | bytea                  |
Indexes:
    "open_id_authentication_associations_pkey" PRIMARY KEY, btree (id)

openid_test_development=# \d open_id_authentication_nonces
                                   Table "public.open_id_authentication_nonces"
   Column   |          Type          |                                 Modifiers
------------+------------------------+----------------------------------------------------------------------------
 id         | integer                | not null default nextval('open_id_authentication_nonces_id_seq'::regclass)
 timestamp  | integer                | not null
 server_url | character varying(255) | default NULL::character varying
 salt       | character varying(255) | not null
Indexes:
    "open_id_authentication_nonces_pkey" PRIMARY KEY, btree (id)


基本的なログインの仕組みを作る

Sessionsコントローラ作成。

$ script/generate controller sessions
      exists  app/controllers/
      exists  app/helpers/
      create  app/views/sessions
      exists  test/functional/
      create  app/controllers/sessions_controller.rb
      create  test/functional/sessions_controller_test.rb
      create  app/helpers/sessions_helper.rb

先にログイン画面を作ってイメージをつかむ。

>> app/views/sessions/new.html.erb

<% form_tag(session_url) do %>
  <p>
    <label for="openid_url">OpenID:</label>
    <%= text_field_tag "openid_url" -%>

    <%= submit_tag 'Sign in', :disable_with => "Signing in&hellip;" %>
  </p>
<% end %>

ログイン後に表示する画面は簡易版でお茶を濁しておく。

>> app/views/sessions/index.html.erb

<% if flash[:error] -%>
  <%= flash[:error] %>
<% end -%>
<% if flash[:notice] -%>
  <%= flash[:notice] %>
<% end -%>

<p>Index Page.</p>

セッション・コントローラはここまでシンプル。authenticate_with_open_id がすべてを処理してくれるので、OpenIDの認証処理についてあれこれ手間をかける必要がない。素晴らしい。Ruby OpenID Libraryのサンプルのように書かなければいけないならOpenID使うの面倒くさいからイヤと言ってしまいそうだが、これなら使える。

>> app/controllers/sessions_controller.rb

class SessionsController < ApplicationController

  def index
  end

  def create
    if using_open_id?
      open_id_authentication
    else
      #TODO:password_authentication
      redirect_to :action => "index"
    end
  end


  protected
    def open_id_authentication
      authenticate_with_open_id do |result, identity_url|
        if result.successful?
          successful_login identity_url
        else
          failed_login result.message
        end
      end
    end


  private
    def successful_login(identity_url)
      session[:user_id] = identity_url
      flash[:notice] = "login successful.(#{session[:user_id]})"
      redirect_to :action => "index"
    end

    def failed_login(message)
      flash[:error] = message
      redirect_to :action => "index"
    end
end

最後に魔法をかける。

>> config/routes.rb

  map.open_id_complete 'session', :controller => "sessions", :action => "create", :requirements => { :method => :get }
  map.resource :session


課題がたくさん

  • ログインフォームは最低でもロゴが表示されるようにしないといけない
  • 認証エラーとか認証拒否がちゃんと拾えていないみたい
  • ユーザ管理がまったくできていないのでユーザ管理機能との統合しなきゃ
  • 複雑なアプリケーションに組み込めるか?
  • パスワード認証と併用するようにできるか?

エラー対処

開発中以下のエラーがでて少し嵌ったがブラウザのCookieのキャッシュクリアしたら直った。

CGI::Session::CookieStore::TamperedWithCookie in SessionsController#new

参考サイト

参考にしてない(まだ読んでない)けど、参考になりそうなページ

スパム対策のためのダミーです。もし見えても何も入力しないでください
ゲスト


画像認証

トラックバック - http://d.hatena.ne.jp/RunOnRails/20080622/1214132171