2012-05-16 14 views
5

Estoy intentando utilizar una publicación de Ajax en una acción. Las solicitudes GET funcionan bien, pero cuando trato de POST, veo una '400 Bad Request' en Firebug y la vista devuelve una respuesta de 'Black hole'.La publicación CakePHP ajax sigue respondiendo 400 Bad Request

Aquí está la solicitud de Jquery:

  $.ajax({ 
      url:"/usermgmt/users/editUser", 
      type:"POST", 
      success:function(data) { 
       alert('Wow this actually worked'); 
       //ko.applyBindings(self); 

      }, 
      error:function() { 
       alert('This will never work'); 
      } 
     }); 

Se debe esto a la configuración de seguridad de la torta o lo que me estoy perdiendo aquí?

+0

Estoy investigando esto y estoy bastante seguro de que es el componente de seguridad que me detiene aquí: http://book.cakephp.org/2.0/en/core-libraries/components/security-component.html – kSeudo

+0

Ok tan si desactivo la seguridad entre sitios con esto: $ this-> Security-> csrfCheck = false; Funciona ..... pero obviamente este no es el camino a seguir :) ¿Alguna idea? – kSeudo

+0

puede publicar el código en/usermgmt/users/editUser – Leo

Respuesta

18

Protección contra la forma de manipulación es una de las características básicas proporcionadas por el componente de seguridad. Siempre que esté habilitado, se tratarán todos los POST como presentaciones de formularios.

Un formulario HTML común codificado a mano no funcionará con el componente de seguridad habilitado, por lo que tampoco lo hará un POST generado por JQuery. Por supuesto, puede usar $this->Security->validatePost = false; o $this->Security->csrfCheck = false; pero luego pierde la protección que proporciona el componente de seguridad.

Para mantener el Componente de Seguridad encendido y funcionando normalmente, debe usar el Ayudante de Formularios de CakePHP para crear el formulario que va a publicar a través de ajax. De esta manera los data[_Token][fields] y data[_Token][unlocked] campos ocultos consiguen generar con sus claves:

<?php 
    echo $this->Form->create('Test',array('id'=>'testform')); 
    echo $this->Form->input('Something'); 
    echo $this->Form->submit(); 
    echo $this->Form->end(); 
?> 

Esto generará algo como esto:

<form action="/your/url" id="testform" method="post" accept-charset="utf-8"> 
    <div style="display:none;"> 
     <input type="hidden" name="_method" value="POST"/> 
     <input type="hidden" name="data[_Token][key]" value="9704aa0281d8b5a2fcf628e9fe6f6c8410d8f07a" id="Token937294161"/> 
    </div> 
    <div class="input text"> 
     <input name="data[Test][Something]" class="required" type="text" id="TestSomething"/> 
    </div> 
    <div class="submit"> 
     <input type="submit" /> 
    </div> 
    <div style="display:none;"> 
     <input type="hidden" name="data[_Token][fields]" value="0c81fda1883cf8f8b8ab39eb15d355eabcfee7a9%3A" id="TokenFields817327064"/> 
     <input type="hidden" name="data[_Token][unlocked]" value="" id="TokenUnlocked281911782"/> 
    </div> 
</form> 

Ahora es sólo una cuestión de la serialización de esta forma en jQuery para que ésta pueda ser enviado con el Ajax POST:

$('#testform').submit(function(event) { 
     $.ajax({ 
      type: 'POST', 
      url: "/your/url", 
      data: $('#testform').serialize(), 
      success: function(data){ 
       alert('Wow this actually worked'); 
      }, 
      error:function() { 
       alert('This will never work'); 
      } 
     }); 
     event.preventDefault(); // Stops form being submitted in traditional way 
    }); 

Ahora bien, si se pulsa el botón de enviar, el POST tendrá éxito.

IMPORTANTE: Debido a que los Tokens de Formulario de ayuda solo se pueden usar una vez con el Componente de seguridad, esta solución solo funciona si solo desea PUBLICAR una vez por generación de página. Si tiene que ser capaz de publicar la misma forma varias veces entre recargas de la página, entonces tendrá que hacer lo siguiente cuando se agrega el componente de seguridad al principio de su controlador:

public $components = array(
    'Security' => array(
     'csrfUseOnce' => false 
    ) 
); 

... esta voluntad permita que los tokens se usen para más de una solicitud. No es como seguro, pero puede combinarlo con csrfExpires para que los tokens caduquen con el tiempo. Todo esto está documentado en el CSRF configuration section of the Cake book.

+1

Muy útil respuesta, ¡gracias! – Dave

+2

Solo quería añadir un poco a esto, ya que el error también se encontrará si JavaScript modifica un campo de entrada 'oculto', ya que el token realiza un seguimiento de esos. Si no desea deshabilitar validatePost, simplemente cambie los campos de ocultos a campos de tipo de texto, luego ocúltelos mediante css (visualizar: ninguno). Esto permitirá que su formulario sea enviado correctamente, incluso si javascript cambia sus campos de entrada. – TeckniX

+0

Respuesta muy buena y detallada, esto me ayudó a salir exactamente del mismo problema y me hubiera llevado un tiempo darme cuenta de que era SecurityComponent. +1 para usted, señor! – Oldskool

0

Hacer Shure usted está poniendo el editUser función en:

public function beforeFilter(){ 
    parent::beforeFilter() 
    $this->Auth->allow('editUser'); 
    } 

interior de UsersController,

Saludos

0

contestación de José faltaba un detalle para mí.Mi formulario y la llamada ajax estaban en index.ctp y llamaban a /controller/edit.ctp para que mi $ this-> Form-> create call necesitara 'action' => '/ controller/edit'.

Cuestiones relacionadas