2010年9月22日水曜日

#appengine の開発環境でfederatedLoginなアプリを動作させる

appengineのfederatedLoginの機能を使ったアプリケーションの場合、開発環境のログイン機能ではcom.google.appengine.api.users.UserからfederatedIdentityの値などが取得できずに不便です。実行時のUserService#isLoggedIn(), UserService#isAdmin(), UserService#getAuthDomain()等はApiProxy.Environmentを自身の実装に置き換えるだけだったので簡単でしたが、federatedLoginの場合はこれらの値を触るだけでは不十分です。
ではいつものようにApiProxy#setDelegate(ApiProxy.Delegte)でいじってやるか!というワケにもいきません。UserService#getCurrentUser()等はRPCされないためです(以前、本家MLで「UserServiceはコストが低い」という話がありましたね。その理由はRPCしない=コストが低い、ということです。このブログでもいつだったかに書いた記憶があります。)。

んじゃどーするのか?といいますと、ApiProxy#getCurrentEnvironment()で取得できるApiProxy#Environment<ApiProxy.Delegate>Map<String, Object>#getAttributes()メソッドが返す値を操作してやるのです。

ApiProxy#Environment<ApiProxy.Delegate>#Map<String, Object>#getAttributes()に以下の要素を設定してやることで、federatedLoginの機能が開発環境でも有効になります。

  1. com.google.appengine.api.users.UserService.is_federated_user
  2. com.google.appengine.api.users.UserService.user_id_key
  3. com.google.appengine.api.users.UserService.federated_identity
  4. com.google.appengine.api.users.UserService.federated_authority

com.google.appengine.api.users.UserService.is_federated_userについてはBoolean.TRUEを設定しておく必要があります。他はすべて文字列を設定すればよく、それぞれの値はfederatedLogin機能を使うときのアレです。

単体テスト環境では、ApiProxy#Environment<ApiProxy.Delegate>Map<String, Object>#getAttributes()が返す値に上記を追加し、ApiProxy#setEnvironmentForCurrentThred()してやれば良いです。
開発サーバ環境でも同じことをすれば良いのですが、私が使っている「専用のFilterとして実装する」という方法のサンプルコードを掲載しておきます。
「独自のApiProxy#Environment<ApiProxy.Delegate>を常に使用する」「createLoginURL()すると、専用のフォームを表示し、そこからのPostの内容に従ってfederatedLoginUser情報を設定する」「web.xml内でinit-paramにfederatedLoginUser情報があれば、それを読み込んで起動時からログイン状態にしておく」等をやっています。
単体テスト環境では、下記のサンプルコードの内部staticクラスとして定義されているFederatedLoginEnvironmentをインスタンス化して、loginメソッドなどでfederatedLogin状態を作り出し、ApiProxy#setEnvironmentForCurrentThred()すれば良いですね。

コメントを投稿