【问题标题】:Play 2.4 disable certain filters set based on request path or method播放 2.4 禁用基于请求路径或方法设置的某些过滤器
【发布时间】:2016-03-29 14:50:43
【问题描述】:

在 Play 2.3 中,我可以根据不同的请求路径或方法禁用某些过滤器。但是,我在 Play 2.4 中找不到方法。 https://www.playframework.com/documentation/2.4.x/ScalaHttpFilters。如何在 Play 2.4 HttpFilters 中获得类似的结果。

这是我在 Play 2.3 中的做法。

object CacheCtrlHeadersFilter extends EssentialFilter {
  def apply(action: EssentialAction) = new EssentialAction {
    def apply(requestHeader: RequestHeader) = {
      action(requestHeader).map { result =>
        result.withHeaders(
            CACHE_CONTROL -> "no-cache, no-store, must-revalidate, private",
            PRAGMA -> "no-cache"
          )
      }
    }
  }
}

import play.api.libs.iteratee._
object FilterChainByRequestHeader {
  def apply[A](action: EssentialAction, filtersFun: (RequestHeader) => List[EssentialFilter]): EssentialAction = new EssentialAction {
    def apply(rh: RequestHeader): Iteratee[Array[Byte], Result] = {
      val chain = filtersFun(rh).reverse.foldLeft(action) { (a, i) => i(a) }
      chain(rh)
    }
  }
}

object Global extends GlobalSettings {

  val securityFilter = SecurityHeadersFilter()
  val defaultFilters = List(securityFilter,
                            CacheCtrlHeadersFilter)

  def filters(rh: RequestHeader) = {
    if (rh.method == "OPTIONS")                       <----------- by method
      defaultFilters.filterNot(_.eq(securityFilter))
    else if (rh.path.startsWith("/apps/google"))      <----------- by path
      defaultFilters.filterNot(_.eq(securityFilter))
    else defaultFilters
  }
  override def doFilter(a: EssentialAction): EssentialAction = {
    FilterChainByRequestHeader(super.doFilter(a), filters)
  }

}

Play 2.4 中的 HttpFilters 中没有可用的 RequestHeader

class Filters @Inject() (
  securityHeadersFilter: SecurityHeadersFilter,
  cacheCtrlHeadersFilter: CacheCtrlHeadersFilter
) extends HttpFilters {

  val filters = Seq(securityHeadersFilter, cacheCtrlHeadersFilter)
}

【问题讨论】:

  • 只是一个想法,但也许您可以扩展过滤器并在其中构建逻辑?
  • @gpgekko 是的,我想过。但我想知道这是否是唯一的解决方案。
  • @gpgekko 另外,如果我构建一个过滤器,如何在 apply 函数中跳过当前过滤器?
  • 我现在没有 Scala 文档(并且我不熟悉 Scala),但我想一个 if 语句只调用 super / 如果为真则改变结果并且不更改/返回在 else 中未更改的结果

标签: scala playframework playframework-2.3 playframework-2.4


【解决方案1】:
object Global extends WithFilters(new CoreActionFilter()) {

}


class CoreActionFilter extends Filter {

  lazy val serviceLogger = Logger("services")

  def apply(nextFilter: RequestHeader => Future[Result])(requestHeader: RequestHeader) = {

    nextFilter(requestHeader).map { result =>

      val action = requestHeader.path match {
        case "/favicon.ico" => s"[ ${requestHeader.remoteAddress.toString}]"
        case _ => s"[ ${requestHeader.remoteAddress.toString}]" + ("[") + requestHeader.tags(Tags.RoutePattern) + ("]") + ("[") + requestHeader.tags(Tags.RouteController) + "." + requestHeader.tags(Tags.RouteActionMethod) + ("]")
      }

      val startTime = System.currentTimeMillis
      val endTime = System.currentTimeMillis
      val requestTime = endTime - startTime
      val token = requestHeader.headers.get("X-Auth-Token")
      serviceLogger.info(s"[$token]" + s"${action}[${requestTime}ms]" + s"[${result.header.status}]")
      result.withHeaders("Request-Time" -> requestTime.toString)

    }(CoreContexts.simpleSqlQuery)

  }
}

【讨论】:

  • 你能解释一下你的答案吗?如何在您提供的方法中跳过过滤器?
  • 请看我的实现:在我的项目中,它也有一个过滤器。我将条件验证放在我的过滤器中。例如:CoreActionFilter。您可以尝试实现 apply 方法来进行条件验证。
【解决方案2】:

我的实现:

类过滤器 @Inject() (corsFilter: CORSFilter,coreActionFilter: CoreActionFilter) 扩展 HttpFilters { def 过滤器 = Seq(corsFilter, coreActionFilter) }

类 CoreActionFilter 扩展过滤器 { def apply(nextFilter: RequestHeader => Future[Result])(requestHeader: RequestHeader) = {

if(/*yourContidion*/) {

  nextFilter(requestHeader).map { result =>

    val action = requestHeader.path match {
      case "/favicon.ico" => s"[ ${requestHeader.remoteAddress.toString}]"
      case _ => s"[ ${requestHeader.remoteAddress.toString}]" + ("[") + requestHeader.tags(Tags.RoutePattern) + ("]") + ("[") + requestHeader.tags(Tags.RouteController) + "." + requestHeader.tags(Tags.RouteActionMethod) + ("]")
    }

    val startTime = System.currentTimeMillis
    val endTime = System.currentTimeMillis
    val requestTime = endTime - startTime
    val token = requestHeader.headers.get("X-Auth-Token")
    serviceLogger.info(s"[$token]" + s"${action}[${requestTime}ms]" + s"[${result.header.status}]")
    result.withHeaders("Request-Time" -> requestTime.toString)

  }(CoreContexts.simpleSqlQuery)
}
nextFilter(requestHeader)

} }

【讨论】:

  • 当您想添加内容时,请编辑您之前的答案,而不是发布新答案
【解决方案3】:

这就是我最终要做的。

class SecurityHeadersFilter extends EssentialFilter {
  def apply(action: EssentialAction) = new EssentialAction {
    def apply(rh: RequestHeader) = {
      action(rh).map { result =>
        if (rh.method != "OPTIONS" && !rh.path.startsWith("/apps/google"))
          result.withHeaders(
              "X-Frame-Options" -> "SAMEORIGIN",
              "Content-Security-Policy" -> "default-src * 'self' 'unsafe-inline' 'unsafe-eval' "
            )
      }
    }
  }
}

class Filters @Inject() (
  gzip: GzipFilter,
  cache: CacheCtrlHeadersFilter,
  cors: CorsFilter,
  security: SecurityHeadersFilter
) extends HttpFilters {
  val filters = Seq(gzip, cache, cors, security)
}

【讨论】:

    【解决方案4】:

    这就是我的实现方式。它正在工作,但并不理想。基本上我们在最外层添加一个WhiteListFilter,来丰富请求,让请求永远不会被过滤掉。

    如果过滤器是关于操纵响应的,那么可以使用相同的过滤器来有效地unset 响应。

    免责声明,我使用文本编辑器键入以下代码只是为了让您获取图片。不能保证它可以编译:

    object WhiteListFilter extends EssentialFilter {
    
      override def apply(next: EssentialAction) = new EssentialAction {
        override def apply(req: RequestHeader) = {
    
          val whiteListedReq =
            // if the filter is about to block some request by headers
            // then append the valid headers, to `whitelist` request
            if (req.method == "OPTIONS") {
              req.copy(headers = req.headers.add("XXX" -> "XXX"))
            } else {
              req
            }
    
          next(whiteListedReq).map {
            resp =>
              // if the filter is about to manipulate response
              // then unset the actions
              if (req.method == "OPTIONS") {
                val headers = resp.headers - "key1" - "key2"
                resp.copy(headers = headers)
              } else {
                resp
              }
          }
        }
      }
    }
    

    【讨论】:

      猜你喜欢
      • 2012-06-16
      • 2020-09-09
      • 2021-02-19
      • 2014-02-23
      • 2020-07-16
      • 2020-12-05
      • 1970-01-01
      • 2010-09-21
      • 2016-01-18
      相关资源
      最近更新 更多