例えば、各コントローラー、メソッド単位で認可の判断をする場合など、メソッド側にパターンマッチを書いてももちろんいいんだけど、以下のように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を返すところでなんだかんだでハマってしまった(^_^;)
リンク
リンク