给定以下EssentialAction
...
object MyController extends Controller {
...
def HasToken(action: Token => EssentialAction) = EssentialAction { request =>
...
// this doesn't compile
val body = request.body match {
case json: JsValue => json.toString
case _ => ""
}
// calculate hash with body content here
...
}
// here is an authenticated action
def getUser(userId: Strign) = HasToken { token =>
Action(parse.json) { request =>
request.body.validate[User] match {
...
}
}
}
}
...我如何在不解析请求的情况下获取请求的主体?
我不需要,也不需要解析
HasToken
中的请求正文,因为该正文将在操作getUser
中进行解析。我只需要正文的原始内容来计算哈希值。HasToken
中的代码无法编译,因为request
是RequestHeader
类型,而我需要一个Request
,它定义了body
。 最佳答案
这对您有用吗?
object MyController extends Controller {
// Your HasToken Action
def Authenticate(action: Token => EssentialAction) = EssentialAction { requestHeader =>
// ... execute logic to verify authenticity using requestHeader
}
// Your action to validate tampering of request body and validity of JSON
def Validate[A](action: Token => Request[A]) = Action(parse.json) { request =>
val body = request.body
body match {
case json: JsValue => json.toString
case _ => ""
}
// calculate hash with body content here
body.validate[User] match {
// ...
}
}
def getUser(userId: Strign) = Authenticate { token =>
Validate { user =>
//.... Continue
}
}
}
身份验证仅使用RequestHeader
验证使用请求正文。 (奖金:正文仅解析一次)
编辑:
问题#1:我不想在Validate中验证主体...因为我需要一个通用的验证机制,无论内容类型(例如用户,消息等)如何都可以在任何地方使用。
如何添加另一个类型参数(使它成为通用类型):
def Validate[A, B](action: Token => Request[A])(implicit reads: Reads[B]) = Action(parse.json) { request =>
// ...
}
问题2:此外,如果令牌验证失败,则不必处理正文(这对于文件上载非常重要,只有在验证成功时才必须执行)。我认为这样最好的方法是在Validate中读取正文的原始内容。
这很容易实现:
def Validate[A, B](action: Token => Request[A])(implicit reads: Reads[B]) = Action(parse.json) { request =>
val body = request.body
body match {
case json: JsValue => json.toString
case _ => ""
}
// calculate hash with body content here and figure out if the body is tampered
if (bodyIsNotTampered) {
body.validate[B] match {
// ...
}
} else {
// log and return Future.successful(BadRequest)
}
}
编辑3:完整解决方案:
import play.api.libs.json.{Json, JsValue, Format}
object CompilationUtils {
class Token
case class User(name: String)
implicit val UserFormat = Json.format[User]
def authenticate = new Token // authentication logic
def isTampered(body: JsValue) = {
val bodyAsStr: String = Json.stringify(body)
// calculate hash with body content here
false
}
}
object MyController extends Controller {
import CompilationUtils._
// Your HasToken Action
def Authenticate(action: Token => EssentialAction) = EssentialAction { requestHeader =>
action(authenticate)(requestHeader) // your execute logic to verify authenticity using requestHeader
}
// Your action to validate tampering of request body and validity of JSON
def Validate[A, B](request: Request[A])(implicit formatA: Format[A], formatB: Format[B]): Either[Result, B] = {
val body = request.body
val bodyAsJsValue = Json.toJson(body)
if (!isTampered(bodyAsJsValue)) {
bodyAsJsValue.validate[B].fold(
valid = res => Right(res),
invalid = err => Left(BadRequest(err.toString))
)
} else {
Left(BadRequest) // Request Tampered
}
}
def getUser(userId: String) = Authenticate { token =>
Action(parse.json) { request =>
Validate(request).fold(
badReq => badReq,
user =>
// continue...
Ok("")
)
}
}
}
关于scala - EssentialAction:如何在不解析请求的情况下获取请求的主体,我们在Stack Overflow上找到一个类似的问题:https://stackoverflow.com/questions/30602256/