SHOEISHA iD

※旧SEメンバーシップ会員の方は、同じ登録情報(メールアドレス&パスワード)でログインいただけます

DeveloperZine(デベロッパージン)- エンジニアの意思決定を支える技術情報メディア ProductZine

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

japan.internet.com翻訳記事

OpenIDとRails:Authentication 2.0

OpenID認証をRuby on Rails 2.0に組み込む方法

インテリジェントな認証システムの実現

 ここからはアプリケーションコードを修正し、ログインコントローラーを実装して、認証システムを構築していきます。

アプリケーションコードの修正

  1. 「app/controllers/application.rb」ファイルを開き、次のauthorizeメソッドを追加します。
  2. def authorize
      unless session[:user_id]
        flash[:notice] = "Please log in"
        # save the URL the user requested so we can hop back to it
        # after login
        session[:jumpto] = request.parameters
        redirect_to(:controller => "/login", :action => "index")
      end
    end
    
    このメソッドは、有効な資格情報がないと実行できない処理をユーザーが要求したときに、その要求を中断してログイン画面にリダイレクトします。
    また、このメソッドは、要求パラメータをセッションの:jumptoシンボルに格納してログイン画面を生成します。ユーザーはログインするとすぐに、最初に要求したURLに転送されます。
  3. 次に、枠組みと共に作成された「todos_controller.rb」を修正する必要があります。下記のように、before_filterを追加します。
  4. class TodosController < ApplicationController
      before_filter :authorize,
        :only => [ :new , :edit, :create, :update, :destroy]
    
      ... rest of the controller as before ...
    end
    
    この処理により、TODO項目を作成または修正する操作には、正常にログインしてからでないとアクセスできなくなります。

ログインコントローラーによる認証の仕組み

 ログインコントローラを実装することにより、ログインの仕組みの最重要部を確認できます。端末で次のコマンドを実行します。

# script/generate controller login

 生成された「app/controllers/login_controller.rb」ファイルを開きます。このファイルをリスト1のように編集します。

リスト1 ログインコントローラ
require 'ostruct'

class LoginController < ApplicationController

  def index
    redirect_to :controller => "todos" if session[:user_id]
  end

  def login
    if using_open_id?
      authenticate
    else
      flash[:error] = "You must provide an OpenID URL"
      redirect_to :action => "index"
    end
  end

  def logout
    session[:user_id] = nil
    redirect_to :action => "index"
  end

  protected
    def authenticate(identity_url = "")
      authenticate_with_open_id(
      params[:openid_url], :required => [:nickname, :email]) do
        |result, identity_url, registration|

        if result.successful?
          @user = OpenStruct.new
          @user.identity_url = identity_url
          @user.nickname = registration["nickname"]
          @user.email = registration["email"]
          session[:user_id] = @user

          jumpto = session[:jumpto] || { :controller => "todos" }
          session[:jumpto] = nil
          redirect_to(jumpto)
        else
          flash[:error] = result.message
          redirect_to :action => "index"
        end
      end
    end

    def root_url
      openid_url
    end
end

 このコントローラには認証の仕組みがすべて含まれているので、順番に見ていきましょう。

indexメソッド

 indexメソッドは、ユーザーが既にログインしている場合はユーザーをWebサイトのメインページ(http://localhost:3000/todos)にリダイレクトし、まだログインしていない場合はログインページ(http://localhost:3000/login)に転送します。まだログインページのビューがありませんので、次のコードを使用して「app/views/login/index.html.erb」ファイルを作成します。

<% if flash[:error] -%>
  <%= flash[:error] %>
<% end -%>
<% form_tag :controller => "login" , :action => "login" do |f| -%>
  <label for="openid_url" >
    OpenId URL:
  </label>
  <%= text_field_tag :openid_url -%>
  <%= submit_tag "Login" -%>
<% end -%>

 これを見ると、従来のようにユーザー名とパスワードを入力するフィールドではなく、ユーザーのOpenID Identifierを受け付けるテキストフィールドが1つだけあります。openid_urlというラベルは慣用的なラベルで、これがあることでブラウザはユーザーのOpenID IdentifierをOpenID対応のWebサイト全体で記憶できます。

loginメソッドとlogoutメソッド

 loginメソッドはログイン処理を扱い、logoutメソッドはアプリケーションからログアウトしたユーザーのデータをセッションからすべて削除します。

 using_open_id?関数はruby-openidライブラリに属する関数で、ユーザーがログインを開始中または終了中であるかどうかを検出します。図3に示すように、ログイン処理ではWebサイトに対して呼び出しが2回行われます。1回目の呼び出しにはログイン処理を開始するOpenID Identifierが含まれ、2回目の呼び出しにはOpenID Providerから返されたユーザー資格情報が含まれます。従って、loginメソッドは2回呼び出され、using_open_id?関数は両方の発生を検出します(これについては、後で詳しく説明します)。

図3 OpenID認証フロー。Webサイトに対して2回の呼び出しが行われます。
図3 OpenID認証フロー。Webサイトに対して2回の呼び出しが行われます。
authenticate関数

 authenticate関数には認証ロジックのほとんどが記述されています。これは、ruby-openidライブラリのauthenticate_with_open_id関数に委任されます。この関数はログイン処理が正常に完了したかどうかに関係なく、その完了時(つまり、Webサイトへの2回目のコールバックの後)に実行されるブロックを受け付けます。このブロックには、次の3つのパラメータを指定できます。

  • resultオブジェクト
  • このオブジェクトは、ログイン処理の有効性を定義します。発生する可能性があるさまざまなエラー(ユーザーがログインをキャンセルした、OpenID Providerが使用できないなど)を調査するメソッドを備えています。
  • identity_urlオブジェクト
  • このオブジェクトには、ユーザーのOpenID Identifierが格納されます。
  • registrationオブジェクト
  • このオブジェクトには、SREG(Simple Registration Extension for OpenID)に基づいて、ユーザーの追加情報が格納されます。

 Simple Registration ExtensionはOpenID仕様に追加された機能で、ProviderとWebサイトでユーザーに関する追加情報を交換できるようにします。例えば、ユーザーの電子メールアドレス、本名、生年月日、その他の個人データを交換できます。ユーザーは個人情報の非開示をOpenID Providerに要求してプライバシーを保護できます。前の例では:optionalディレクティブではなく:requiredディレクティブを使用して、ユーザーの資格情報以外にもニックネームと電子メールアドレスを要求しています。

 OpenIDによりSREGでも認証機能が向上します。従来の仕組みを採用したWebサイトでは、ユーザーは登録フォームに必要事項をすべて入力する必要があり、サードパーティごとに個人データを何度も繰り返し指定しなければなりません。

 最後に、authenticateメソッドは:user_idセッション変数にユーザーデータをすべて格納し、redirect_to(:jumpto)文によってユーザーを最初の要求ページにリダイレクトします。

routes.rbファイルとroot_urlメソッドの設定

 前述したように、loginメソッドは2回呼び出されます。2回目の呼び出しでは、OpenID Providerからユーザーブラウザへのリダイレクトが指示されます。このリダイレクトを正しく行うには、最後に2つの処理を実行する必要があります。

 まず、次のように「routes.rb」構成ファイルに適切な経路を定義する必要があります(名前付き経路を使用していることに注意してください)。

map.openid "login",
  :controller => "login" ,
  :requirements => { :method => :get }

 次に、その名前付き経路をログインコントローラのroot_urlメソッドで参照する必要があります。

def root_url
  openid_url
end

 これにより、OpenID Providerに対して、ログイン後にユーザーがリダイレクトされるURLは、ログイン要求の送信元ドメインと同じドメイン(信頼されたルート)に属することが保証されます。

 最後の処理が完了すると、適切に認証され識別されたユーザーのみ、アプリケーションは受け付けるようになります。また、追加情報を使用してユーザーにさらに便利な機能を提供することもできます。

 例えば、ユーザーが新しいTODO項目を作成するときに、ユーザー名と電子メールアドレスを既に入力しておくことができます。これを行うには、「todos_controller.rb」ファイルを再度開きnewメソッドを次のように修正します。

def new
  @todo = Todo.new
  @todo.person = session[:user_id].nickname
  @todo.email = session[:user_id].email

  respond_to do |format|
    format.html # new.html.erb
    format.xml  { render :xml => @todo }
  end
end

次のページ
その他の多くの機能

この記事は参考になりましたか?

japan.internet.com翻訳記事連載記事一覧

もっと読む

この記事の著者

japan.internet.com(ジャパンインターネットコム)

japan.internet.com は、1999年9月にオープンした、日本初のネットビジネス専門ニュースサイト。月間2億以上のページビューを誇る米国 Jupitermedia Corporation (Nasdaq: JUPM) のニュースサイト internet.comEarthWeb.com からの最新記事を日本語に翻訳して掲載するとともに、日本独自のネットビジネス関連記事やレポートを配信。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

Riccardo Govoni(Riccardo Govoni)

2003年からJ2EE開発者としてイタリアの金融サービス会社に勤務。ソフトウェアアーキテクトとして従来の銀行システムのWebフロントエンドの設計に従事。物理学修士。SCJP(Sun Certified Java Programmer)資格を持つ。

※プロフィールは、執筆時点、または直近の記事の寄稿時点での内容です

この記事は参考になりましたか?

この記事をシェア

CodeZine(コードジン)
https://codezine.jp/article/detail/2514 2008/06/16 14:00

イベント

CodeZine編集部では、現場で活躍するデベロッパーをスターにするためのカンファレンス「Developers Summit」や、エンジニアの生きざまをブーストするためのイベント「Developers Boost」など、さまざまなカンファレンスを企画・運営しています。

新規会員登録無料のご案内

  • ・全ての過去記事が閲覧できます
  • ・会員限定メルマガを受信できます

メールバックナンバー