OpenIDで認証するCGIのサンプル
OpenIDで認証するCGIのサンプルです。taslamの日記 - 認証APIいろいろをRubyで使うを参考に(というかほとんどコピペですが)作成させて頂きました。
OpenIDとは?
OpenIDでの認証の流れ
サービス「Hoge」の利用をOpenIDで認証を受けたユーザーに許可する場合の流れは次のようになります。なお、認証には、はてなのOpenID認証機能を使うものとします。
- 1.認証者がIDを示すURL(Claimed Identifier)をサービス「Hoge」(Consumer)に提示します。
- OpenIDのIDはURLです。はてなの場合「http://www.hatena.ne.jp/<ユーザーID>/」が該当します。
- 以下のサンプルでは、初回アクセス時にIDを入力するフォームを表示して、指定してもらうようにしています。
- 2.サービスは、指定されたIDから、Identity Provider(この場合、はてなの認証サイト)を特定し、そこにリダイレクトします。
- Identity ProviderはIDを示すURLのサイトのヘッダに書いてあります。
- 3.ユーザーは、リダイレクトされた認証サイトで認証を受けます。認証後、Identity Providerによって、サービス「Hoge」に再度リダイレクトされます。
- 4.サービスはIdentity Providerから渡された認証結果を受け取り、認証が完了していればユーザーに利用を許可します。
ここの下のほうにあるシーケンス図がわかりやすい。
サンプル
$ gem install ruby-openid
- CGIのセッションの記録にはCGI::Session::PStoreを使うこと!
- デフォルトのCGI::Session::FileStoreを使うと、「uses_extensiontがない」とかいうエラーになります。
#!/usr/local/bin/ruby require 'rubygems' require 'openid' require 'openid/store/filesystem' require 'cgi' require 'cgi/session' require 'cgi/session/pstore' BASE_URL = 'http://unageanu.sakura.ne.jp/blog-samples/080608' AUTH_FORM = <<FORM <html> <head> <meta http-equiv="Content-Type" content="text/html; charset=UTF-8"> </head> <body> <h3>OpenIDでの認証サンプル</h3> <form method="post"> <input id="openid_identifier" name="openid_identifier" type="text" value="http://www.hatena.ne.jp/<ユーザーID>/" style="width:300px" /> <input name="commit" type="submit" value="認証" /> </form> </body> FORM cgi = CGI.new session = CGI::Session.new(cgi, { 'tmpdir' => "./tmp", 'database_manager' => CGI::Session::PStore # PStoreを使用しないと、「uses_extensiontがない」とかいうエラーになる。 }) store = OpenID::Store::Filesystem.new('./tmp') consumer = OpenID::Consumer.new(session, store) if session['verified_identifier'] # ログイン済み cgi.out() { "#{session['verified_identifier']}でログイン済み" } else if cgi['openid_identifier'] != nil && cgi['openid_identifier'].length > 0 # 2.認証画面でIdentifierが入力され送付されたら認証処理を開始する。 identifier = cgi['openid_identifier'] check_id_request = consumer.begin( identifier.to_s.chomp ) # リダイレクト先を取得 redirect_url = check_id_request.redirect_url( BASE_URL, BASE_URL+"/index.cgi") # 認証サイトにリダイレクト puts cgi.header({'status' => '302 Found', 'Location' => redirect_url }) elsif cgi['openid.mode'] != nil && cgi['openid.mode'].length > 0 # 3.認証結果を処理 hash = cgi.params.clone.inject({}) {|h,e| h.store(e[0], e[1][0]) # 配列で渡されるのを展開する。 h } res = consumer.complete( hash, BASE_URL+"/index.cgi") case res.status when OpenID::Consumer::FAILURE # 認証に失敗した。メッセージがoid_res.messageで取得可能。 cgi.out { "認証失敗 : " << res.message } when OpenID::Consumer::SUCCESS session['verified_identifier'] = res.display_identifier cgi.out { "#{ session['verified_identifier']}でログイン完了" } when OpenID::Consumer::CANCEL # 認証をユーザがキャンセルした cgi.out { "キャンセルされた" } end else # 1.認証画面を表示 cgi.out{ AUTH_FORM } end end