mixi OpenIDで「マイミクシィだけの掲示板」を作ろう(Perl編)

今日はmixi OpenIDという認証サービスが発表され、各所で報じられている。

mixiOpenIDのOPになったからと言って何がどうなるというわけでもないでしょ」と思っていた人も、「マイミクシィ認証」「コミュニティ認証」という2つの仕様には少し驚いただろう。前者は「○○さんとマイミクシィであるか」、後者は「○○というコミュニティに入っているか」をそれぞれ証明するものだ。これらを使えば、単にmixiのユーザが使えるというだけに留まらない、人や関心でのつながりを生かしたアプリケーションを作れることになる。

以下のコードはPerlCGIとして実装した「マイミクシィしか使えない掲示板」のサンプルだ。ただし今回は話を簡単にするため「掲示板っぽく見える画面を出すだけ」にしてある。本当に書き込めたり閲覧できたり、という機能を作りたい方は自分で補っていただきたい。

また、OpenIDのRPになるためにNet::OpenID::Consumerを使っている。OpenID 2.0に対応したものをSix Apartさんが配布しているので予めインストールしておく。 http://code.sixapart.com/trac/openid/browser/branches/openid2/perl/Net-OpenID-Consumer
#!/usr/local/bin/perl

use strict;
use utf8;
use CGI;
use LWP::UserAgent;
use Net::OpenID::Consumer;
use Encode;

my $query = CGI->new;
$query->charset("utf-8");

my $mixi_id=4012; # このIDを持つ人のマイミクシィでないとログインできない
my $claimed_id = "https://id.mixi.jp/$mixi_id/friends";
my $csr = Net::OpenID::Consumer->new(
  ua => LWP::UserAgent->new,
  args => $query,
  consumer_secret => "hoge",
  );

if($query->param('openid_url')){ # loginボタンを押された時
  if(my $cident = $csr->claimed_identity($claimed_id)){
    # SREG1.1でニックネームを取りたい
    $cident->set_extension_args("http://openid.net/extensions/sreg/1.1", {
      required => "nickname"});

    # リダイレクト先を決める
    my $check_url = $cident->check_url(
      return_to  => URI->new($query->url.'?verify=1')->as_string,
      trust_root => $query->url,
      delayed_return => "checkid_setup",
      );

    # リダイレクトする
    print $query->redirect(-uri => $check_url);
  }
}elsif($query->param('verify')){ # 戻ってきた時
  if(my $setup_url = $csr->user_setup_url){
    print $query->redirect(-uri => $setup_url);
  }elsif($csr->user_cancel()){
    login_page($query, 'キャンセルされました');
  }elsif($query->param('openid.claimed_id')!~/https:\/\/id.mixi.jp\/$mixi_id\/friends\/\d+/){
    login_page($query, 'マイミクシィでないのでログインできません');    
  }elsif(my $identity = $csr->verified_identity){
    print $query->header, '<h1>ログイン完了!!</h1>'."\n";
    # ニックネームを添えて、掲示板風の画面を出す
    my $nickname = decode("utf-8",$query->param('openid.sreg.nickname'));
    if(!($nickname)){$nickname="名無し";} # ニックネームを出さない設定にしていたら「名無し」にする
    print "<h2>".$nickname."さんのオレオレ掲示板</h2>\n<form>\n";
    print "<textarea cols=70 rows=10></textarea><br>\n";
    print "<input type=\"submit\" value=\"書き込み\">\n";
    print "</form>\n";
    print "<hr>\n";
  } else {
    login_page($query);
  }
} else { # login前のページを表示する時
  login_page($query);
}

sub login_page {
    my ($query, $message) = @_;
    $message = $message ? $message= "<p class='error'>$message</p>" : '';
    print encode("utf-8",$query->header), <<PAGE;
<html lang="ja">
<head>
<meta http-equiv="Content-Type" content="text/html; charset=utf-8">
<title>mixi OpenID login</title>
</head>
<body>

<h1>オレオレ掲示板</h1>

$message

ログインしてみよう:
<a href="index.cgi?openid_url=https://mixi.jp"><img src="b_150.gif" alt="mixiでログイン" border="0"></a>
</body>
</html>
PAGE
}



↑ログイン前の画面。「mixiでログイン」の画像ボタンはhttp://developer.mixi.co.jp/openid/button にあるものを使う。



↑ログインを試みるとmixiのページに飛ぶ。注意事項をよく読んで同意する。



↑ログインに成功した様子。mixiSREGによるnicknameの引渡しをサポートしているので、このようにニックネームを取得できる。「そんなもの外に出したくない!」という人はhttp://mixi.jp/openid_edit.pl により、出す出さないを選択できる。デフォルトは出すようになっている。



↑今回のキモは「マイミクシィにしかログインさせない」機能だ。これはmixiのFAQによると「mixi.jp から返ってきた Claimed Identifier がhttps://id.mixi.jp/X/friends/[ユーザー ID] であることを RP 側でチェック」せよ、とある。実際にはマイミクシィでない場合、チェックする前に上の画像のように怒られるのだが、確認用コードは入れておいたほうがよい。