2015-06-02 2 views
4

Учитывая следующее EssentialAction ...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

Обязанность HasToken неясна. Где логика hasToken? Я вижу только, что вы пытаетесь получить доступ к телу для вычисления хэша полезной нагрузки. Также неясно, чего вы хотите. Вы хотите, чтобы он скомпилировался? Если это так, я должен спросить, почему ваша подпись HasToken является Token => EssentialAction, а не Token => Request .. Если вы хотите, чтобы HasToken не анализировал тело, то почему бы не отправить токены в RequestHeader, если это то, что вы хотите? –

+0

'HasToken' проверяет, что заголовок запроса имеет действительный веб-токен JSON ... и хеш используется для проверки того, что запрос не был взломан. Во всяком случае, эти данные бесполезны для моего вопроса. Я просто спрашиваю, как получить необработанное содержимое запроса (мне нужно его вычислить хеш, который должен соответствовать тому, который содержится в токене). – j3d

+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 
    } 
    } 
} 
  • аутентификации использует только 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("") 
    ) 
    } 
    } 
} 
+0

Спасибо за ваш ответ. Я не хочу проверять тело в 'Validate' ..., так как мне нужен общий механизм проверки, который можно использовать везде независимо от типа содержимого (например, пользователя, сообщения и т. Д.).Кроме того, если проверка маркера не выполняется, тело не нужно обрабатывать (это важно в случае загрузки файла, которое должно выполняться тогда и только тогда, когда проверка прошла успешно). Это, на мой взгляд, лучший вариант - прочитать сырое содержимое тела в «Validate». – j3d

+0

@ j3d: Я обратился к вашим комментариям. Пожалуйста, ознакомьтесь с обновленным ответом. –

+0

... проблема в том, что анализатор может отличаться в зависимости от запроса. Например, это 'parse.Json', если тело содержит JSON, но в случае multipart/form-data (т. Е. Загрузка файла) синтаксический анализатор будет' fsBodyParser', настраиваемый парсер, который хранит входящие данные непосредственно в MongoDB. – j3d

Смежные вопросы