Будет ли это работать на вас?
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
- Validation использует тело запроса. (Bonus: Body только разобран один раз)
EDIT:
Вопрос № 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)
}
}
EDIT 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("")
)
}
}
}
Обязанность HasToken неясна. Где логика hasToken? Я вижу только, что вы пытаетесь получить доступ к телу для вычисления хэша полезной нагрузки. Также неясно, чего вы хотите. Вы хотите, чтобы он скомпилировался? Если это так, я должен спросить, почему ваша подпись HasToken является Token => EssentialAction, а не Token => Request .. Если вы хотите, чтобы HasToken не анализировал тело, то почему бы не отправить токены в RequestHeader, если это то, что вы хотите? –
'HasToken' проверяет, что заголовок запроса имеет действительный веб-токен JSON ... и хеш используется для проверки того, что запрос не был взломан. Во всяком случае, эти данные бесполезны для моего вопроса. Я просто спрашиваю, как получить необработанное содержимое запроса (мне нужно его вычислить хеш, который должен соответствовать тому, который содержится в токене). – j3d
«Во всяком случае, эти детали бесполезны для моего вопроса». => Я так не думаю, если вы принимаете мой ответ :) –