PlayFramework Actionメソッドを拡張した独自アクションを作成する

個人開発したアプリの宣伝
目的地が設定できる手帳のような使い心地のTODOアプリを公開しています。
Todo with Location

Todo with Location

  • Yoshiko Ichikawa
  • Productivity
  • Free

スポンサードリンク

例えば、各コントローラー、メソッド単位で認可の判断をする場合など、メソッド側にパターンマッチを書いてももちろんいいんだけど、以下のようにActionメソッドを拡張したメソッドに渡して透過的に確認することもできる。

def index() = SignedAction{ implicit request =>
 Ok("authorized")
}

以下は作成例。


拡張Actionクラスを作成する

ActionBuilderで新しいActionメソッドのみを定義することも可能なんだけど、そのメソッド内で処理に応じてResultを返す場合、AbstractControllerを継承した拡張Controllerクラスとした方が結果的に楽。だと思う。

package controllers
import javax.inject.Inject
import play.api.mvc._
import scala.concurrent.{ExecutionContext, Future}

class AuthenticateController  @Inject() (val cc:ControllerComponents)
  extends AbstractController(cc) {

  def SignedAction() = new ActionBuilder[Request, AnyContent]{

    override def parser: BodyParser[AnyContent] = cc.parsers.defaultBodyParser

    override protected def executionContext: ExecutionContext = cc.executionContext

    override def invokeBlock[A](request: Request[A], block: (Request[A]) => Future[Result]) = {
      if( true == false ){
        Future( Redirect("/unauthorized")  )(cc.executionContext)
      }else {
        block(request)
      }
    }
  }
}

ActionBuilderの各メソッドを実装する。invokeBlockがSignedActionの実行部分になり、引数blockが渡された高階関数になる。

上の例では、認証が通らない場合、/unauthorizedにリダイレクトして、認可が通った場合、渡された関数を実行する。といったイメージの関数実装です。

また、このようにResult型を返す必要がない場合は、Controllerを継承せずにActionBuilderImplの実装でActionメソッドを作成することができる。


Controllerから拡張したActionメソッドを呼び出す。

継承での利用

class HomeController @Inject()(controllerComponents: ControllerComponents) extends AuthenticateController(controllerComponents) {

  def index() = SignedAction(){ implicit request =>
    Ok("authorized")
  }

  def unauthorized() = Action{ implicit request =>
    Ok("unauthorized")
  }
}

移譲での利用

class HomeController @Inject()(val auth:AuthenticateController, implicit val db:Database, controllerComponents: ControllerComponents)extends AbstractController(controllerComponents) {

  def index() = auth.SignedAction(){ implicit request =>
    Ok("authorized")
  }

  def unauthorized() = Action{ implicit request =>
    Ok("unauthorized")
  }
}

最初はResultを返さずにActionBuilderImplで実装してて、簡単に実装できたんだけど、Resultを返すところでなんだかんだでハマってしまった(^_^;)