複数マイミクシィ認証
通常のOpenIDのRP(Relying Party)ではこんなことはしないだろうが、mixi OpenIDでは十分にありえる話だと思って試しに作ってみた。「Aさんのマイミクシィで、かつBさんのマイミクシィ」だけが使える、という複数条件による認証だ。
コードは前回のエントリ「mixi OpenIDで「マイミクシィだけの掲示板」を作ろう(Perl編)」のものを微修正し、リダイレクトを2回行うようにした。
#!/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_id1=2; # このIDを持つ人のマイミクシィでないとログインできない my $mixi_id2=4012; # さらに、このIDを持つ人のマイミクシィでないとログインできない my $claimed_id1 = "https://id.mixi.jp/$mixi_id1/friends"; my $claimed_id2 = "https://id.mixi.jp/$mixi_id2/friends"; my $csr = Net::OpenID::Consumer->new( ua => LWP::UserAgent->new, args => $query, consumer_secret => "hoge", ); if($query->param('openid_url')){ # loginボタンを押された時 if(my $cident1 = $csr->claimed_identity($claimed_id1)){ # 1度目のリダイレクト先を決める my $check_url = $cident1->check_url( return_to => URI->new($query->url.'?verify=1')->as_string, trust_root => $query->url, delayed_return => "checkid_setup", ); # 1度目のリダイレクトをする 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_id1\/friends\/.+/){ # 2度目のリダイレクト if(my $cident2 = $csr->claimed_identity($claimed_id2)){ # SREG1.1でニックネームを取りたい $cident2->set_extension_args("http://openid.net/extensions/sreg/1.1", { required => "nickname"}); # 2度目のリダイレクト先を決める my $check_url2 = $cident2->check_url( return_to => URI->new($query->url.'?verify=1')->as_string, trust_root => $query->url, delayed_return => "checkid_setup", ); # 2度目のリダイレクトをする print $query->redirect(-uri => $check_url2); } }elsif($query->param('openid.claimed_id')!~/https:\/\/id.mixi.jp\/$mixi_id2\/friends\/.+/){ 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 }
これで問題なく実行できた。ガイドラインにも、そんなことをやっちゃいかんとは書かれていない。利用同意画面が2度出てくるのは面倒じゃないか?という場合には(本当にそれでよいのかという議論はありそうだが)「この外部サイトの場合常に同意する」ボタンを押してしまえばよい。
ものすごく安直な実装のため、「Aさんのマイミクシィで、かつBさんのマイミクシィ『でない』」のような要件には対応できない。2つの認証を直列につながず、別個に非同期に行えばできるかもしれない。