2013年10月15日火曜日

play-pac4j : Play! Framework 2.2 で OAuth(失敗 -> 2.1 では成功)

ちょっと前のエントリで Play! Framwork で twitter4j を使うのに SecureSocial というのを使ってみましたが、別のものということで今度は pac4j というのを使ってみます。定義によると
pac4j is a Profile & Authentication Client for Java (it's a global rebuilding of the scribe-up library)
だそうです。それをさらに Play! Framework から利用しやすいように play-pac4j というものがあるようですね。早速使ってみます。

まずは dependency の解決です。上のガイドに従うと、Twitter を使うためには、play-pac4j_java と pac4j-oauth が必要なようですね。Maven の central repo では最新はそれぞれ 1.1.1 と 1.4.1 です。以下のように build.sbt に追加します。(このファイル、2.x では project/Build.scala だったはずなんですが、変わったんですね・・・)

libraryDependencies ++= Seq(
  javaJdbc,
  javaEbean,
  cache,
  "org.twitter4j" % "twitter4j-core" % "3.0.4",
  "org.pac4j" % "play-pac4j_java" % "1.1.1",
  "org.pac4j" % "pac4j-oauth" % "1.4.1"
)  

前回やったように、IntelliJ IDEA を一度止めて play idea してから開きなおすのが手っ取り早いようです。ではコードの変更です。
  1. コントローラーが継承しているクラスを Controller から JavaController に
  2. Global.onStart() で TwitterClient を登録
  3. ログインを要求したいコントローラーメソッドに @RequiresAuthentication を追加
  4. routes に callback を追加
具体的には
1
import org.pac4j.play.java.JavaController;

public class Application extends JavaController {
2
public class Global extends GlobalSettings {
    @Override
    public void onStart(Application application) {
        final TwitterClient twitter = new TwitterClient(CONSUMER_KEY, CONSUMER_SECRET);
        final Clients clients = new Clients("http://localhost:9000/callback", twitter);
        Config.setClients(clients);
3
    @RequiresAuthentication(clientName="TwitterClient")
    public static Result top() {
4
# For pac4j
GET   /callback               org.pac4j.play.CallbackController.callback()
POST  /callback               org.pac4j.play.CallbackController.callback()
GET   /logout                 org.pac4j.play.CallbackController.logoutAndRedirect()
おお、結構作業量が少なくていい感じ。早速実行してみましょう。
[info] play - Application started (Dev)
Uncaught error from thread [play-akka.actor.default-dispatcher-7] shutting down JVM since 'akka.jvm-exit-on-fatal-error' is enabled for ActorSystem[play]
java.lang.AbstractMethodError
あっさりオワタw
まだ 2.2 がサポートされてないんですね。この方も嘆いてますが、Play! Framework ってバージョン間の互換性がなさすぎる・・・。

仕方ないので Play! Framework を 2.1.5 にしてみます。2.1.5 で play new して作った雛形から、Build.scala をコピーして、build.sbt 内に加えた変更を移動します。あとは念のため diff で差分が出た build.properties とか plugins.sbt とかを直していざテスト。

おっ!
うまくいきました。これは結構簡単。

最後にお約束の twitter4j のインスタンス作り。
    @RequiresAuthentication(clientName="TwitterClient")
    public static Result login() throws TwitterException {
        final TwitterProfile profile = (TwitterProfile) getUserProfile();
        TwitterFactory factory = new TwitterFactory(new ConfigurationBuilder().setOAuthConsumerKey(CONSUMER_KEY).setOAuthConsumerSecret(CONSUMER_SECRET).build());
        Twitter tw = factory.getInstance(new AccessToken(profile.getAccessToken(), profile.getAccessSecret()));
これでうまくいきました。