ユーザー認証の設定
通常、認証が必要なアプリケーションでは、ユーザーが認証されているかチェックし、ログイン画面を表示する処理が必要です。
GoogleアカウントAPIを利用した認証では、アプリケーションがAPIを利用し、認証状態をチェックしてログイン画面へリダイレクトさせる方法と、web.xmlに認証が必要なuriを定義して自動的に処理させる方法の2通りがあります。
本稿では、後者のweb.xmlへの設定により認証を行う方法を利用します。
LiftFilterを拡張する
ローカル開発環境でGoogleアカウントAPIを利用した認証を行う場合、ログイン画面のURLは"http://localhost:8080/_ah/login"のようなURLになります。この"/_ah/"で始まるURLをLiftが処理しないように、Liftで提供されているLiftFilterクラスを拡張する必要があります。
"src/main/scala/bootstrap/liftweb/"ディレクトリに、"LiftFilterForAppEngine.scala"というファイル名で以下の内容のソースコードを新規に作成します。
package bootstrap.liftweb
import net.liftweb.http.{Req, LiftRules}
class LiftFilter extends net.liftweb.http.LiftFilter {
override def isLiftRequest_?(session: Req): Boolean =
!session.request.uri.startsWith("/_ah/") && super.isLiftRequest_?(session)
}
このLiftFilterクラスは、LiftFilterクラスが持つisLiftRequest_?関数をオーバーライドして、"/_ah/"で始まるリクエストはLiftで処理しないようにしてあります。
web.xmlへの設定
"src/main/webapp/WEB-INF"にある"web.xml"を修正します。太字の部分は追加してください。
<web-app>
<filter>
<filter-name>LiftFilter</filter-name>
<display-name>Lift Filter</display-name>
<description>The Filter that intercepts lift calls</description>
<filter-class>bootstrap.liftweb.LiftFilter</filter-class> *1
</filter>
...中略...
<security-constraint>
<web-resource-collection>
<url-pattern>/*</url-pattern> *2
</web-resource-collection>
<auth-constraint>
<role-name>*</role-name> *3
</auth-constraint>
</security-constraint>
<security-constraint>
<web-resource-collection>
<url-pattern>/mailSender/*</url-pattern>
</web-resource-collection>
<auth-constraint>
<role-name>admin</role-name>
</auth-constraint>
</security-constraint>
</web-app>
*1では、先ほど用意したLiftFilterクラスを利用するようにServletFilterの設定を変更しておきます。
*2が、認証を必要とするurlのパターンです。今回はすべてのurlで認証が必要なように設定しています。*3は、認証に必要なロールです。"*"は、Googleアカウントを持つユーザーなら誰でも認証を行えるような設定です。このロールを"admin"に指定すると、アプリケーションの管理者のみがアクセスできるように制限することが可能です。
2つ目のsecurity-constraintタグで指定されているのは、この後解説するリマインダメール送信の際に使用する定義なので、ここで同時に追加しておきます。
ログアウトリンクの追加
ログインへの誘導は自動で行われますが、ログアウトはユーザーが明示的に行うので、ログアウト用のリンクを用意しておく必要があります。
ログアウト処理自体は、GoogleアカウントAPIでログアウト用URLを取得してリダイレクトするだけです。リダイレクトだけのためにテンプレートを用意するのは手間です。ここでは、テンプレートを用意しないで処理できるようにしておくため、LiftViewという仕組みを利用してログアウトさせます。
LiftViewは、テンプレートの代わりに直接XHTMLを関数から戻り値として返すことができる仕組みです。LiftViewトレイトを継承したクラスをviewディレクトリに用意しておくだけです。
"src/main/scala/demo/view"ディレクトリに、Logout.scalaを以下の内容で作成します。
package demo.view
...中略...
class Logout extends LiftView{
def dispatch = Map("index" -> logout _ ) *1
def logout = {
val userService = UserServiceFactory.getUserService *2
redirectTo( userService.createLogoutURL("/") ) *3
}
}
このLogoutクラスは、dispatch関数(*1)でURLに対してどの関数を処理に割り当てるかを定義しています。今回は"/logout"というリンクを処理させたいため、index(/に対応)をlogout関数に割り当てています。
logout関数は、GoogleアカウントAPIでUserServiceを取得し(*2)、UserServiceのcreateLogoutURLメソッドを呼び出して得られるURLにリダイレクトさせています。
"/logout"というURLをLogoutクラスに処理させるために、Boot.scalaにSiteMapの定義を追加します。この定義は、通常のテンプレートのURLの指定がViewのクラス名に変わっただけです。
val entries = Menu(Loc("Home", List("index"), "Topページ")) ::
Menu(Loc("Save", List("save"), "イベントを作る")) ::
Menu(Loc("Logout", List("logout"), "ログアウト")) :: Nil
動作確認
ここまで設定して、mvn packageコマンドでコンパイルし、dev_appserverコマンドで開発サーバを起動して"http://localhost:8080"にアクセスすると、次のような開発環境用のログイン画面が表示されます。

ここで入力する内容は、任意のユーザーアカウント名で構いません。実際に存在しないアカウント名でも認証されたことになります。チェックボックスにチェックしておくと、管理者としてログインしたものとして扱われます。
