我喜欢用提取器编写喷雾指令。我的一个项目的简化示例:
def loggedInUser: Directive[Option[User] :: HNil] = headerValue {
case Cookie(cookies) => cookies.find(_.name === usrCookie) ∘ extractUserFromCookie
case _ => None
} | reject(NoUserLoggedInRejection)
def authOpt(usrOpt: Option[User], usr: String): Directive0 =
authorize(usrOpt.filter(_.login ≠ usr).isEmpty)
然后在您的路由文件中,您可以使用提取器:
pathPrefix("path") {
loggedInUser { user =>
authOpt(user, Clients.client) {
path("path") {
get {
complete {
html.page() // i'm using Twirl as a fe engine
}
}
}
}
}
如果没有用户登录,则会引发拒绝,并单独处理:
implicit val customRejectionHandlers = RejectionHandler {
case NoUserLoggedInRejection :: _ =>
ctx => ctx.redirect("/auth", StatusCodes.SeeOther)
}
在安全示例的情况下,这不是最好的,但我认为这已经足够清楚了
添加
headerValue
注释中的指令示例:
// Lets define a extractor for the Host header from the request
val hostExtractor: HttpHeader => Option[String] = {
case Host(host, port) => Some(host)
case _ => None
}
// Then some path
val route = {
path("somePath") {
post {
headerValue(hostExtractor) { host =>
complete(host)
}
}
}
}
大多数这样的指令都是通过extract
指令实现的,它接受一个 type: 的函数RequestContext ⇒ T
并返回T
。例如headerValue
还通过以下方式实现extract
:
extract(_.request.headers.mapFind(protectedF)).flatMap {
case Some(Right(a)) ⇒ provide(a)
case Some(Left(rejection)) ⇒ reject(rejection)
case None ⇒ reject
}