endless pulse

どっくんどっくんふるえる毎日を過ごしています

Play framework 2.3 for Scalaで、認証してみる

注:2015/7に書いた記事です。

どうもこんにちは、えみーです。
Play framework 2.3 for Scalaで、認証してみよう!と思ったんですが、公式ドキュメント系がイマイチ見つけられず…ちょっと試行錯誤したので、おぼえがき程度に書いておきます。

認証の方針

先のセッション管理でも参考にさせていただいた、Javaでの記事を参考にて考えました。
参考:ステートレスなPlay2でログイン状態を管理する - C Sharpens you up

異なる点は以下。

  • クッキーは、Playのセッションメソッドを通して使う(Playのセッションはクライアントサイドのクッキーとして実現されている)
  • Scalaである

参考にした記事では、play.mvc.Security.Authenticatorをextendsしているんですが、play.mvc._ はJava用のAPIなので、Scala用のAPIであるplay.api.mvc.Securityからなんやかんやしたいです。
というわけで、Play framework 2.0.4のドキュメントで以下のものがあったので、参考にして、認証用のtraitを作ります。
Scala Security - 2.0.4
(2.3.x用の、上記に該当するページが見つけられず…。ただ、APIを確認すると、play.api.mvc.Security.Authenticatedメソッドは2.3.xでも存在してます。また、APIのAuthenticatedメソッドの解説に、認証用trait及びそれを使ったController内のアクション記載の説明もあるので、そのまま参考にしてみます。play.api.mvc.SecurityのAPIドキュメント

あと、Playのセッションではタイムアウトは、2.3以降はできるようになったようです。(参考:Migration23 - 2.3.x
とすると、「セッションが切れたかどうか」は、単純にセッションの有無で判断してもよさそうです。
もちろん、二重ログインがどうとか他の問題はありますが、そのあたりはいったん置いておいきます。。

やったこと

以下に実際にやったものの覚書を置いておきます。

  • セッションタイムアウトの設定
  • Authenticateチェック用のトレイト
  • 認証を必要とする画面表示やアクション(コントローラ)
セッションタイムアウトの設定

そんなわけで、まずセッションクッキーの名前「PLAYSESSION」と、タイムアウトの設定を30分にします。
conf/application.conf

session.cookieName=PLAYSESSION
session.maxAge=30m
Authenticateチェック用のtrait

Authenticator.scala

package controllers

import play.api._;
import play.api.mvc._;

trait Secured{
  // セッションがあるとき、取得する値。 getの中身は欲しいキーを入れる。
  def username(request: RequestHeader) = request.session.get(Security.username)
    
  // セッションがないときのふるまい。例は新規セッションを作ってログインページを表示する。
  def onUnauthorized(request : RequestHeader) = {
    Results.Ok(views.html.login()).withNewSession
  }
  
  // セッションのあるないをチェックしてからActionを実行するためのメソッド。Controllerで使用する。
  def withAuth(f: => String => Request[AnyContent] => Result) = {
    Security.Authenticated(username, onUnauthorized) { user =>
      Action(request => f(user)(request))
    }
  }
認証を必要とする画面表示やアクション(コントローラ)の記述

Sample.scala

package controllers

import play.api._
import play.api.mvc._

object SampleController  extends Controller with controllers.Secured {

  // ログインしていない場合のアクション
  def showTop = Action { implicit request =>
    Ok("Please login!")
  }

  // ログインしている場合のアクション
  def showMembersPage = withAuth { username => implicit request =>
    Ok("Hello, " + username + "!")
  }
}