無料で使えるシステムトレードフレームワーク「Jiji」 をリリースしました!

・OANDA Trade APIを利用した、オープンソースのシステムトレードフレームワークです。
・自分だけの取引アルゴリズムで、誰でも、いますぐ、かんたんに、自動取引を開始できます。

OpenIDで認証するCGIのサンプル

OpenIDで認証するCGIのサンプルです。taslamの日記 - 認証APIいろいろをRubyで使うを参考に(というかほとんどコピペですが)作成させて頂きました。

OpenIDとは?

@IT - 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から渡された認証結果を受け取り、認証が完了していればユーザーに利用を許可します。

ここの下のほうにあるシーケンス図がわかりやすい。

サンプル

  • ruby-openid」を使用しています。以下のコマンドでインストールできます。
$ 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

動作確認はこちらから