認証機能確認
OpenIDが気になっていたので、それのサンプルを作ってみる。RailsにHatenaとLiveDoorの認証を組み込んだことがなかったので、そちらも併せて組み込んでみておく。この3つができればメジャーどころはかなりサポートできるとおもう。
前提
- Rails1.2.6
- Ruby1.8.6 P114
準備
#/usr/local/ruby1.8/bin/gem install ruby-openid (2.0.4がインストールされた)
OpenID1.0と2.0両方に対応している模様
概念
基本的な概念は他の認証とさほど変わりない。おおよそ以下の流れとなる
入力ページ->情報作成してロケーション->情報受け
構築
1.入力ページ
ちょっと面倒な部分もあるのでソースを見ながら確認する
ログイン部分は以下のような感じ。見事に何もない
require "openid" require 'openid/extensions/sreg' require 'openid/extensions/pape' require 'openid/store/filesystem' class UserController < ApplicationController def index login render :action => 'login' end def login end end
Viewも全然たいしたことをしてない
user/login.rhtml <p>OpenID ログインテスト</p> <form method="get" accept-charset="UTF-8" action='<%= url_for :action => 'start' %>'> <p> open-ID: <input type="text" class="openid" name="openid_identifier" /></p> <p> 種別 <%=radio_button_tag "id_type",0,true%>OpenID <%=radio_button_tag "id_type",1,false%>Hatena <%=radio_button_tag "id_type",2,false%>LiveDoor </p> <input type="submit" value="ログイン" /> </form>
openIDのなかで、HatenaとLiveDoorは処理を分けてある。これはHatenaとLiveDoorのIDさえ入力してくれればURL部分は補助しようというのが目的なので実態として合ってもなくても問題無い
2.情報作成からロケーション
この部分が他の認証より一回り面倒くさい。ただ、一回作ってしまえば後は同じなので、まあ定型処理といえる
class UserController < ApplicationController def start begin # ユーザが入力したopenid_identifierを元にOpenIDリクエストを作成 # HatenaとLiveDoorの時は頭のhttp://...を付与するだけ id_url = "" if 1 == params[:id_type].to_i id_url = "http://www.hatena.ne.jp/" + params[:openid_identifier] + "/" elsif 2 == params[:id_type].to_i id_url = "http://profile.livedoor.com/" + params[:openid_identifier] + "/" else id_url = params[:openid_identifier] end #ロケーションする先のurlを作る oidreq = consumer.begin(id_url) # 認証サーバ(OP)からの戻り先URL(completeアクションのURL) return_to = url_for :action => 'complete', :only_path => false # このサーバを識別するためのrealm realm = url_for :action => 'index', :only_path => false # 利用者をOPのログイン画面(OP EndPoint)へと誘導する redirect_to(oidreq.redirect_url(realm, return_to)) #エラーを補足する rescue OpenID::DiscoveryFailure @error = "OpenID::DiscoveryFailure"; end end #この下が不思議な処理。サンプルから取得したんだが、ローカルに一端セッションを自力で #作っているらしい。非常に奇妙だ。分散サーバーにしたときなど大丈夫なんだろうか private def consumer if @consumer.nil? dir = Pathname.new(RAILS_ROOT).join('db').join('cstore') store = OpenID::Store::Filesystem.new(dir) @consumer = OpenID::Consumer.new(session, store) end return @consumer end end
3.情報受けページ
ロケーションするときに戻りページを指定しておいたので、completeアクションがコールされる。
class UserController < ApplicationController def complete #パラメータを作成 parameters = params.reject{|k,v|request.path_parameters[k]} # いま自分がいるURLがデータ取得に必要らしいので、作成 current_url = url_for(:action => 'complete', :only_path => false) # 戻り値を解析し,OpenID::Responseクラスのオブジェクトを作成 @oidresp = consumer.complete(parameters, current_url) #ステータスによってログインの成功不成功をキャッチ if OpenID::Consumer::SUCCESS == @oidresp.status @mes = "login 成功" elsif OpenID::Consumer::CANCEL == @oidresp.status @mes = "ログインがキャンセルされました" else @mes = "認証に失敗しました" end end end
ログインに成功するとOpenID::Responseオブジェクトが作成でき以下のメソッドでユーザを特定できるID(URL)が取得できる。これでログイン完了となる。他の要素については特にもらえない
@oidresp.identity_url
プライベートメソッドがすこし気持ちわるいが、Hatena,YahooのOpenID1.0/2.0ともにこれでデータがとれた。ライブドアはどうしてもダメだったが他のサイトのOpenIDでのログインで試してもダメなので他の要素が何かあるのだろう。