その他の多くの機能
今までにRailsを使用した経験がある方ならば、本稿で説明している実装では従来の既存の認証フレームワーク(restful_authenticationまたはact_as_authenticated)をまったく使用していないことに気付くかもしれません。これには前述したように、OpenID認証は既存の認証ロジックに依存しないからです。
また、Railsのopen_id_authenticationプラグインへの依存を避けたり、柔軟性を高めたりする必要がある場合は、ruby-openidライブラリに直接アクセスすることもできます。リスト2に別バージョンのログインコントローラを示します。
このログインコントローラでは、関数呼び出しとパブリッククラスを直接使用しています(コードが長くなっています)。さらに大きな違いとして、このログインコントローラではアプリケーションとOpenID Providerとのハンドシェークプロセスで使われる一時的なデータを、データベースではなくファイルシステムに格納しています。
require "openid" require 'user' class OpenID::Consumer attr_accessor :referer end class LoginController < ApplicationController def login if session[:user] @login = session[:user] render :action => 'status' , :layout => false return end if params[:login] @login = OpenID::OpenidUser.from_params(params[:login]) if @login.validate store_dir = OPENID_STORE_DIR store = OpenID::FilesystemStore.new(store_dir) consumer = OpenID::Consumer.new(session, store) consumer.referer = @request.env['HTTP_REFERER'] req = consumer.begin(@login.openid) case req.status when OpenID::FAILURE @login.errors.add(:openid,"Unable to find OpenID server") when OpenID::SUCCESS # simple registration procedure to extract # the email, nickname and fullname (if available) req.add_extension_arg('sreg','required','email,nickname') req.add_extension_arg('sreg','optional','fullname') @redirect_url = req.redirect_url(BASE_URL, url_for( :action => 'complete')) # save the consumer for later use session[:consumer] = consumer session[:temp_login] = @login redirect_to @redirect_url else # should never arrive here raise "Unreachable code" end end end render :action => 'status' , :layout => false end def complete if session[:user] @login = session[:user] render :action => 'status' , :layout => false return end consumer = session[:consumer] session[:consumer] = nil # consume consumer if consumer.nil? render :action => 'status' , :layout => false return end res = consumer.complete(params) if res.status == OpenID::FAILURE flash[:login_notice] = "Login has been rejected" elsif res.status == OpenID::SUCCESS sreg = res.extension_response('sreg') if sreg.length > 0 # finalize login @login = session[:user] = session[:temp_login] @login.email = sreg['email'] @login.nickname = sreg['nickname'] @login.fullname = sreg['fullname'] session[:temp_login] = nil end elsif res.status == OpenID::CANCEL flash[:login_notice] = "Login has been canceled." else # unknown response type flash[:login_notice] = "OpenID provider has returned" + " an unknown response type" end redirect_to consumer.referer end def logout session[:user] = session[:temp_login] = nil render :action => 'status', :layout => false end end
OpenIDは多くの可能性を秘めている
OpenIDサービスには明確な利点があります。開発者の立場からは、コードの重複や複雑さが軽減し管理上の手間が省けます。ユーザーの立場からは、より統一感のあるWebエクスペリエンスが得られます。
ただし、本稿ではOpenIDの広大な世界についてごく表面的に説明したにすぎません。新しいOpenID 2.0の仕様、サービスのディスカバリとデリゲーションの仕組み、XRDS(Extensible Resource Descriptor Sequence)フォーマット、Stateless Relying Partyなどまだ紹介していない機能が数多くあります。
また、ruby-openidライブラリについても簡単にしか説明していません。例えば、ruby-openidライブラリは、前述したRelying Partyのクライアントライブラリではなく、Rails OpenID Providerのセットアップにも対応しています。
OpenIDイニシアチブはオープンであるため、必要があればいくらでも深いところまで掘り下げていくことができるのです。
