[英]Play Framework 2.2 action composition returning a custom object
我正在尝试创建一个自定义的play.api.mvc.Action
,它可用于根据请求填充CustomerAccount
并将CustomerAccount
传递给控制器。
在Play 2.2.x的文档之后,我创建了一个Action
和ActionBuilder
但我似乎无法从操作中返回CustomerAccount
。
我目前的代码是:
case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request)
case class Account[A](action: Action[A]) extends Action[A] {
lazy val parser = action.parser
def apply(request: Request[A]): Future[SimpleResult] = {
AccountService.getBySubdomain(request.host).map { account =>
// Do something to return the account like return a new AccountWrappedRequest?
action(AccountWrappedRequest(account, request))
} getOrElse {
Future.successful(NotFound(views.html.account_not_found()))
}
}
}
object AccountAction extends ActionBuilder[AccountWrappedRequest] {
def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = {
// Or here to pass it to the next request?
block(request) // block(AccountWrappedRequest(account??, request))
}
override def composeAction[A](action: Action[A]) = Account(action)
}
注意:这将无法编译,因为block(request)
函数需要一种我无法填充的AccountWrappedRequest
类型。 它将在使用直接Request
时进行编译
最终,我希望能够将此帐户操作与身份验证操作相结合,以便可以将CustomerAccount
传递到身份验证操作,并且可以根据该客户的帐户提供用户身份验证。 然后我想将客户帐户和用户传递给控制器。
例如:
Account(Authenticated(Action))) { request => request.account; request.user ... }
Account(Authenticated(Action))) { request => request.account; request.user ... }
或更好的作为不需要自定义请求对象的单个对象。
我不确定这是否是最好的方法,但我设法提出了一个似乎运作良好的解决方案。
关键是匹配请求将其转换为AccountWrappedRequest
内的invokeBlock
然后再将其传递给下一个请求。 如果链中的另一个Action期望来自链中较早操作的值,则可以类似地将请求转换为您需要访问请求参数的类型。
从原始问题更新示例:
case class AccountWrappedRequest[A](account: CustomerAccount, request: Request[A]) extends WrappedRequest[A](request)
case class Account[A](action: Action[A]) extends Action[A] {
lazy val parser = action.parser
def apply(request: Request[A]): Future[SimpleResult] = {
AccountService.getBySubdomain(request.host).map { account =>
action(AccountWrappedRequest(account, request))
} getOrElse {
Future.successful(NotFound(views.html.account_not_found()))
}
}
}
object AccountAction extends ActionBuilder[AccountWrappedRequest] {
def invokeBlock[A](request: Request[A], block: (AccountWrappedRequest[A]) => Future[SimpleResult]) = {
request match {
case req: AccountRequest[A] => block(req)
case _ => Future.successful(BadRequest("400 Invalid Request"))
}
}
override def composeAction[A](action: Action[A]) = Account(action)
}
然后在另一个Action(在我的情况下为Authenticated操作apply()
的apply()
方法内部,您可以类似地执行:
def apply(request: Request[A]): Future[SimpleResult] = {
request match {
case req: AccountRequest[A] => {
// Do something that requires req.account
val user = User(1, "New User")
action(AuthenticatedWrappedRequest(req.account, user, request))
}
case _ => Future.successful(BadRequest("400 Invalid Request"))
}
}
您可以在ActionBuilder中将操作链接在一起
override def composeAction[A](action: Action[A]) = Account(Authenticated(action))
如果然后将AuthenticatedWrappedRequest
传递给控制器,则可以访问request.account
, request.user
和所有常用请求参数。
正如您所看到的,有几种情况下响应未知会产生BadRequest
。 实际上,就我所知,这些应该永远不会被调用,但它们只是在那里。
我很想得到关于这个解决方案的一些反馈,因为我对Scala还是比较新的,我不确定是否有更好的方法来做同样的结果,但我希望这对某人也有用。
我写了一个独立的小(ish)示例来完成你正在寻找的东西:
https://github.com/aellerton/play-login-example
我放弃了尝试使用play框架中存在的Security
类。 我相信他们很好,但我无法理解他们。
简要指南......
在示例代码中,控制器声明为使用AuthenticatedRequests
特征:
object UserSpecificController extends Controller with AuthenticatedRequests {
...
}
使用RequireAuthentication
操作强制任何页面要求身份验证(或重定向以获取它):
def authenticatedIndex = RequireAuthentication { implicit request: AuthenticatedRequest[AnyContent] =>
Ok("This content will be accessible only after logging in)
}
使用AbandonAuthentication
操作完成AbandonAuthentication
:
def signOut = AbandonAuthentication { implicit request =>
Ok("You're logged out.").withNewSession
}
请注意,为此,您必须覆盖AuthenticatedRequests
特征中的方法,例如:
override def authenticationRequired[A](request: Request[A]): Future[SimpleResult] = {
Future.successful(
Redirect(routes.LoginController.showLoginForm).withSession("goto" -> request.path)
)
}
还有更多; 最好看看代码。
HTH安德鲁
声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.