2

如何在功能测试中获取 CSRF Token?在会话中保存令牌并在 URL 中提交它是行不通的。

"The `send` action" should {
  "return status code 400 if subject is invalid" in new WithApp with Context {
    val token = CSRF.Token(42.toString)
    val Some(result) = route(FakeRequest(POST, helper.CSRF(routes.ContactUs.send())(token).toString())
      .withFormUrlEncodedBody(
        ("subject" -> "invalid"),
        ("name" -> "Lucky Luke"),
        ("email" -> "test@test.com"),
        ("message" -> "test")
      )
      .withSession(TOKEN_NAME -> token.toString)
    )

    status(result) must equalTo(BAD_REQUEST)
    contentType(result) must beSome("application/json")
    charset(result) must beSome("utf-8")
}

编辑

token.toString不会将令牌作为字符串返回。访问器token.value返回一个可以在会话中发送的适当令牌。所以一个工作示例是:

"The `send` action" should {
  "return status code 400 if subject is invalid" in new WithApp with Context {
    val token = CSRF.Token(42.toString)
    val Some(result) = route(FakeRequest(POST, helper.CSRF(routes.ContactUs.send())(token).toString())
      .withFormUrlEncodedBody(
        ("subject" -> "invalid"),
        ("name" -> "Lucky Luke"),
        ("email" -> "test@test.com"),
        ("message" -> "test")
      )
      .withSession(TOKEN_NAME -> token.value)
    )

    status(result) must equalTo(BAD_REQUEST)
    contentType(result) must beSome("application/json")
    charset(result) must beSome("utf-8")
}
4

1 回答 1

1

您的解决方案有效,但为了不对每个请求都执行此操作并进行更清晰的测试,您可以使用自定义GlobalSettings. 这做了两件事:删除 csrf 检查过滤器,但仍然在会话中提供 csrf 令牌,因此 csrf 助手不会阻塞。

object TestGlobal extends WithFilters(FakeCSRF)
object FakeCSRF extends Filter{
  def apply(next: (RequestHeader) => Result)(request: RequestHeader) = {
    next(CSRF.addRequestToken(request,CSRF.generate))
  }
}

然后为您的测试定义一个自定义范围:

trait testApp extends Scope with Around{
  def around[T](t: => T)(implicit evidence$1: AsResult[T]) = {
    Helpers.running(FakeApplication(withGlobal = Some(TestGlobal)))(AsResult(t))
  }
}

现在,在您的测试中,您可以执行以下操作:

"The `send` action" should {
  "return status code 400 if subject is invalid" in new testApp {
    val Some(result) = route(FakeRequest(POST, routes.ContactUs.send())
     .withFormUrlEncodedBody(...)
  }
}

请注意,测试代码中没有提到 CSRF。

警告:如果您不路由您的虚假请求而是直接调用控制器,这将不起作用。将不会使用 TestGlobal,因此您需要使用更详细的解决方案。

于 2013-09-23T14:19:31.027 回答