2008年5月11日日曜日

OpenID対応機能作成してみました。Java(openid4java)編。

OpenIDで認証処理を試してみました。
と、いっても
http://code.google.com/p/openid4java/wiki/SampleConsumer
にサンプルがありますのでこれをそっくり真似ただけです。
http://test.ukauka.net/testapp/login/に今回作ってみたものを置いてみました。
サンプルはcobbyというフレームワークで作っています。
openid4javaのインストールですが、maven2を使うと楽です。
作成したcobbyプロジェクトのpom.xmlに
リポジトリを追加し
<repository>
<id>alchim.snapshots</id>
<name>Achim Repository Snapshots</name>
<url>http://alchim.sf.net/download/snapshots</url>
<snapshots />
</repository>
<dependencies>
</dependencies>
内に下記を追加します。
<dependency>
<groupId>org.openid4java</groupId>
<artifactId>openid4java-consumer</artifactId>
<version>0.9.5-SNAPSHOT</version>
</dependency>
これで0.9.5がインストールされます。
あ、説明忘れてましたが、環境はEclipse3.4m6にm2eclipseプラグインとか入れてます。
こちらのサイトの記事にある環境を導入しました。
Eclipse + Maven2 + Tomcat + Seasar2 の開発環境ベスト!?プラクティス
この環境作っとくと、ライブラリをどっかから探してくる手間が大分省けます。プロジェクトを右クリックしてmaven、依存関係の追加で、パッケージ名入れると外部のリポジトリから必要なjar探してきてどんどんダウンロードしてくれます。らくちんです。(ただ、慣れるとリポジトリにないライブラリを手動でインストールするのが面倒になってきます)
maven2とかeclipseを使わない場合でしたら、
http://openid4java.googlecode.com/files/openid4java-0.9.3-bundle.jarをダウンロードして解凍してください。
拡張子はjarですが中にさらにopenid4java-0.9.3.jarとopenid4java-0.9.3-sources.jarが入ってますので取り出してlibに配置しましょう。
0.9.4はうまくいかない? という記事を見かけたことがあるので0.9.3が無難だと思います。0.9.3は私も試してみて問題ありませんでした。0.9.4は試していません。
以下アクション部分のコードです。例外処理は適当です。
LoginAction.java
package net.ukauka.test.app.action;
import java.util.List;
import javax.servlet.http.HttpServletRequest;
import javax.servlet.http.HttpServletResponse;
import javax.servlet.http.HttpSession;
import org.openid4java.consumer.ConsumerManager;
import org.openid4java.consumer.VerificationResult;
import org.openid4java.discovery.DiscoveryInformation;
import org.openid4java.discovery.Identifier;
import org.openid4java.message.AuthRequest;
import org.openid4java.message.ParameterList;
import org.seasar.cubby.action.Action;
import org.seasar.cubby.action.ActionResult;
import org.seasar.cubby.action.Direct;
import org.seasar.cubby.action.Forward;
/**
* ログインアクション
* @author futti
*/
public class LoginAction extends Action {
public HttpServletResponse response;
public HttpServletRequest request;
public ConsumerManager consumerManager;
public String message; //結果画面に出すメッセージ
public String identifier; //formから入力するopenid
private static String targetURL = "http://test.ukauka.net/testapp/login/verify"; //openidプロパイダの処理後に表示するurl
/**
* 初期表示画面
* @return Forward
*/
public ActionResult index() {
return new Forward("index.jsp");
}
/**
* 認証処理
* @return Forward
*/
public ActionResult auth() {
try {
List discoveries = consumerManager.discover(identifier); // ユーザーから入力のあったopenidプロパイダを探しに行って、プロパイダの情報を取得してきます。
DiscoveryInformation discovered = consumerManager.associate(discoveries); //アソシエーション確立を行います。アソシエーションの応答情報が取得できます。
HttpSession session = request.getSession(true);
session.setAttribute("discovered", discovered); //ベリファイでもアソシエーションの応答情報を使うのでセッションに保持します。
String returnURL = targetURL;
AuthRequest authReq = consumerManager.authenticate(discovered, returnURL); //認証を行います。
String url = authReq.getDestinationUrl(true); //遷移先のURLを取得します。
response.sendRedirect(url); //プロパイダのログイン画面へ遷移します。
} catch (Exception e) {
e.printStackTrace();
}
return new Direct();
}
/**
* 検証処理
* @return Forward
*/
public ActionResult verify() {
ParameterList openidResp = new ParameterList(request.getParameterMap()); //プロパイダから遷移してきた際にURLに付加されているパラメータを取得します。
HttpSession session = request.getSession(true);
DiscoveryInformation discovered = (DiscoveryInformation) session.getAttribute("discovered"); //セッションからアソシエーション情報を取得します。
StringBuffer receivingURL = new StringBuffer();
receivingURL.append(targetURL);
String queryString = request.getQueryString();
if (queryString != null && queryString.length() > 0) {
receivingURL.append("?").append(queryString);
}
VerificationResult verification = null;
String url = receivingURL.toString();
try {
verification = consumerManager.verify(url, openidResp, discovered); //ベリファイを行います。
} catch (Exception e) {
}
Identifier verified = null;
if (verification != null) {
verified = verification.getVerifiedId(); //ユーザーIDを取得します。ユーザーIDが取得できない場合は失敗です。
}
if (verified != null) {
message = "成功:id=" + verified.getIdentifier();
} else {
message = "失敗:" + verification.getStatusMsg();
}
return new Forward("result_s.jsp");
}
}

verification = consumerManager.verify(url, openidResp, discovered);
で使用するURLなんですが、サンプルではrequest.getRequestURLから取得しているんですが、cubbyだと返ってくる値が実際のパスとは違っていてエラーになりました。仕方ないんで固定値を設定しています。
これで動作させると、openID入力して送信→openIDプロパイダの画面で認証処理→結果を受け取るという一連の流れが確認できます。認証が成功するとIDが取得できるのでそれを自分のサイトでユーザーと紐付けるようにすればいいと思います。
これで動作することは確認できたんですが、Yahoo Japan!のopenIDはローカル環境(http://localhost:8080/)からだとエラーになりました。サーバーにアップしてそこからやると問題なかったのですが。
はてなのopenIDだとローカルでも問題なかったので、ちょっと試してみたいとかいう場合ははてなでやると楽かもしれません。
<pre>でコードを囲むとはみ出しますね……。

3 件のコメント:

  1. ローカル環境だとエラーとありますが、
    具体的にどのようなエラーでしたか?
    80以外のポートでopenIDを実装してテストしたら、yahooのサイトで
    「このサイトには現在ログインできません。しばらく時間をおいてから再度お試しください。」
    となってしまいました。これと同じ現象でしょうか?
    mixiやyahoo.comではうまく動いたのですが、、、
    もしよろしければエラーメッセージを教えていただきたいです。
    よろしくお願いいたします。

    返信削除
  2. Yahoo JapanのOpenID

    Yahoo JapanのOpenIDを使ってみたんだけど、リダイレクトをかけた際に、
    「このサイトには現在ログインできません。しばらく時間をおいてから再度お試しください。」
    とでてしまう。
    いろ...

    返信削除
  3. ちょっと試しただけで今手元に動く環境がないんで、詳細は思い出せないんですが、確か「このサイトには現在ログインできません。しばらく時間をおいてから再度お試しください。」が出たと思います。

    返信削除