扩展SecureActionBuilder以在解析正文之前验证请求

时间:2014-09-28 14:42:56

标签: scala playframework securesocial

我正在编写一个Web应用程序,它将多部分文件作为输入并将它们上传到S3实例。由于某些文件可能非常大,我使用自定义Body Parser将块发送到S3。

我想在上传文件之前对请求进行验证(以检查用户是否有权限/足够的空间等)。从阅读Play文档来看,似乎扩展ActionBuilder是正确的方法。我注意到在SecureSocial中有一个SecureActionBuilder,我相信我应该扩展它以构建一个安全的动作(这就是我想要的)。

我尝试了这个简单的测试,看看是否可以打印出userId,因此可以根据用户执行操作。

object FileValidationAction extends SecuredActionBuilder {
  def invokeBlock[A](request: SecuredRequest[A], block: SecuredRequest[A] => Future[SimpleResult]) = {
    Logger.info("User id is " + request.user.userProfile.userId)
    block(request)
  }
}

然而,该方法从未被调用过。

接下来,我尝试从SecuredActionBuilder对象中重写该方法:

object FileValidationAction extends SecuredActionBuilder {
  override def invokeBlock[A](request: Request[A], block: SecuredRequest[A] => Future[SimpleResult]) = {
    val securedResult: Option[SecuredRequest[A]] = request match {
      case r: SecuredRequest[A] => Option(r)
      case _ => None
    }
    Logger.info("Calling action ------- WOO!")
    securedResult match {
      case Some(r) =>
        block(r)
      case _ =>
        Future.successful(Forbidden)
    }
  }
}

该方法被调用,但进入的请求不是我希望的SecuredRequest。

如何使用自定义正文解析器构建SecuredAction,我可以在完成(甚至启动)上传之前对其进行验证?

编辑:

为了澄清,我将使用以下方法签名调用Action:

def upload = FileValidationAction(streamingBodyParser(streamConstructor)) { request =>

1 个答案:

答案 0 :(得分:3)

问题在于您没有调用SecuredActionBuilder中的原始代码,该代码实际检查用户是否存在并构造SecuredRequest实例。

这样的事情应该有效:

// A sample usage of the action
def checkFile = FileValidationAction { request =>
    Ok("")
  }

// The builder implementation
  object FileValidationAction extends FileValidationActionBuilder {
    def apply[A]() = new FileValidationActionBuilder()
  }

  class FileValidationActionBuilder(authorize: Option[Authorization[DemoUser]] = None) extends SecuredActionBuilder(authorize) {
    def validateFile[A](block: SecuredRequest[A] => Future[SimpleResult]): SecuredRequest[A] => Future[SimpleResult] = { securedRequest =>
      Logger.info(s"User id is ${securedRequest.user.main.userId}")
      block(securedRequest)
    }

    override def invokeBlock[A](request: Request[A], block: (SecuredRequest[A]) => Future[SimpleResult]): Future[SimpleResult] = {
      invokeSecuredBlock(authorize, request, validateFile(block))
    }
  }

您需要在计划使用此操作的控制器中添加此内容。如果您需要在多个控制器中使用它,那么创建一个可以用此扩展的特性。

另请注意,在此示例代码中,我使用的是样本中的DemoUser类型。您需要将其更改为您在应用中使用的类型以表示用户。