MixiがOpenIDプロバイダになったので、遊んでみようと思った。mixiなら大抵アカウント持ってるし、友達に勧める時でもマイミクシィという繋がりがあるので、OpenIDを使ってもらう心理的抵抗が他のプロバイダよりちょっと低いかな、と思う。
まずOpenIDの仕組みがよく分からんのだが、とりあえず認証先URLのhttp://mixi.jp/にアクセスすると、こんなレスポンスヘッダが帰ってくる。
HTTP/1.x 200 OK Date: Sun, 24 Aug 2008 12:58:04 GMT Server: Apache X-Dealer: 034084 Cache-Control: no-cache Pragma: no-cache X-XRDS-Location: https://mixi.jp/xrds_server.pl Vary: Accept-Encoding Content-Encoding: gzip Content-Length: 4570 Content-Type: text/html; charset=EUC-JP Connection: close
X-XRDS-Locationなる見た事のないヘッダが返ってきている。そこに書かれているURLにアクセスしてみると
<?xml version="1.0" encoding="UTF-8"?> <xrds:XRDS xmlns:xrds="xri://$xrds" xmlns:openid="http://openid.net/xmlns/1.0" xmlns="xri://$xrd*($v*2.0)"> <XRD> <Service priority="0"> <Type>http://specs.openid.net/auth/2.0/server</Type> <Type>http://openid.net/sreg/1.0</Type> <Type>http://openid.net/extensions/sreg/1.1</Type> <Type>http://openid.net/srv/ax/1.0</Type> <URI>https://mixi.jp/openid_server.pl</URI> </Service> </XRD> </xrds:XRDS>
こんなXMLが返ってきた。ここに書かれているhttps://mixi.jp/openid_server.plはOpenIDログインしようとするとリダイレクトされるURLだ。
このURIに正しい手続きでアクセスすればOpenID利用同意ページが表示される。同意、またはキャンセルをクリックすると元ページにリダイレクトされる。このリダイレクトURLのクエリストリングに認証成功、キャンセル、失敗という情報が付加されて、元サーバに伝わるようだ。
何となく分かったので詳細については後で仕様書を眺めてみる。どういう動きをしているのか分かれば仕様書も読みやすいってもんだ。とりあえず実際にopenid-rubyというライブラリを使って認証するだけのCGIを書いてみた。
#!/usr/local/bin/ruby -Ku require "cgi" require "cgi/session" require "cgi/session/pstore" require "openid" require "openid/store/filesystem" require "erb" cgi = CGI.new session = CGI::Session.new(cgi, "database_manager" => CGI::Session::PStore, "tmpdir"=>"./tmp" ) store = OpenID::Store::Filesystem.new('./tmp') consumer = OpenID::Consumer.new(session, store) def h str ERB::Util.h str end def cgi.erb template self.out("status" => "OK", "type" => "text/html", "charset" => "utf-8") { File.open(template) { |f| ERB.new(f.read).result } } end def cgi.redirect url puts self.header("status" => "REDIRECT", "Location" => url) end flash = "" selfurl = "http://" + cgi.server_name + ":" + cgi.server_port.to_s + cgi.script_name if cgi["openid_identifier"].length > 0 # cgi['openid_identifier']だと怒られる。理由は前エントリ参照 id = cgi.params['openid_identifier'][0] # パラメータで認証プロバイダを指定できるが、mixiでやってみるテストなのでmixiに固定する id = "mixi.jp" begin openid_auth_req = consumer.begin(id) cgi.redirect openid_auth_req.redirect_url(selfurl , selfurl) rescue flash = "OpenIDの認証プロバイダが見つからなかったようだ(" + $!.to_s + ")" cgi.erb "openid_login.cgi.erb" end elsif cgi['openid.mode'].length > 0 params = Hash.new cgi.params.each {|key, val| params[key] = val.first } openid_res = consumer.complete( params, selfurl ) case openid_res.status when OpenID::Consumer::FAILURE flash = "認証できませんでした" cgi.erb "openid_login.cgi.erb" when OpenID::Consumer::CANCEL flash = "えー、ログインしないのー?" cgi.erb "openid_login.cgi.erb" when OpenID::Consumer::SUCCESS session["user"] = openid_res.display_identifier cgi.redirect selfurl when OpenID::Consumer::SETUP_NEEDED flash = "MixiのOpenIDでログインしてね" cgi.erb "openid_login.cgi.erb" else flash = "なんかよくわからんエラー?" + openid_res.class.to_s cgi.erb "openid_login.cgi.erb" end elsif session["user"].nil? flash = "MixiのOpenIDでログインするよ" cgi.erb "openid_login.cgi.erb" else cgi.erb "openid_auth.cgi.erb" end
いくつか注意点