鉴于以下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
。
答案 0 :(得分:3)
这对你有用吗?
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
}
}
}
编辑:
问题#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("")
)
}
}
}