1

On a domain I have my Yii 2.0 web application with a method in a controller that handles the POST request. Below is de code inside my controller class.

public function behaviors()
{
    return [
        'access' => [
            'class' => AccessControl::className(),
            'rules' => [
                [
                    'actions' => [
                        'my-method',
                    ],
                    'allow' => true,
                ],
            ],
        ],
         'verbs' => [
             'class' => VerbFilter::className(),
             'actions' => [
                 'my-method' => ['post'],
             ],
         ],
    ];
}

public function actionMyMethod()
{
    Yii::$app->controller->enableCsrfValidation = false;

    $response = Yii::$app->response;
    $response->format = \yii\web\Response::FORMAT_XML;

    return ['msg' => 'OK!'];
}

On another domain I have a simple page (Not Yii 2.0 application) that sends an AJAX request with POST method using pure JavaScript. Below is the code.

var xmlhttp;
if (window.XMLHttpRequest) {
     xmlhttp = new XMLHttpRequest();
} else {
     xmlhttp = new ActiveXObject("Microsoft.XMLHTTP");
}
xmlhttp.open("POST", "http://my-domain.com/controller-name/my-method", true);
xmlhttp.setRequestHeader("Content-type","application/x-www-form-urlencoded");
xmlhttp.send("id=Henry");
xmlhttp.onreadystatechange = function() {
     if (xmlhttp.readyState==4 && xmlhttp.status==200) {
          var responseXml = xmlhttp.responseXML;
          txt=" ";
          x=responseXml.getElementsByTagName("msg");
          for (i=0;i<x.length;i++) {
               txt = txt + x[i].childNodes[0].nodeValue;
          }
          alert(txt);
     }
}

Everytime I tried to run this above JavaScript code, it said POST 400 (Bad Request) in the Console. If I change from POST to GET, it works fine. Can someone tell me what I missed? What is wrong with the code above?

O Connor
  • 4,236
  • 15
  • 50
  • 91
  • The `onreadystatechange` handler should be added before send() is called, though this might not be the problem. – robsch May 11 '17 at 15:16

1 Answers1

1

If you want to disable CSRF validation for individual action(s) you need to do it in beforeAction event handler because CSRF token is checked before action runs (in beforeAction of yii\web\Controller).

/**
 * @inheritdoc
 */
public function beforeAction($action)
{            
    if ($action == 'my-method') {
        Yii::$app->controller->enableCsrfValidation = false;
    }

    return parent::beforeAction($action);
}

Official docs:

This answer is related, but I didn't mention such details there, updated it as well.

Community
  • 1
  • 1
arogachev
  • 33,150
  • 7
  • 114
  • 117
  • @ Arogachev as you might have seen in my code I do have this code in my method Yii::$app->controller->enableCsrfValidation = false; to disable the CSRF validation for that specific method. Any other suggestion? – O Connor May 28 '15 at 09:16
  • Sorry, overlooked that. Updated the answer. – arogachev May 28 '15 at 09:20