Yii2: How to allow CORS on non-restfull API

17,255

Just add to your API controller:

/**
 * List of allowed domains.
 * Note: Restriction works only for AJAX (using CORS, is not secure).
 *
 * @return array List of domains, that can access to this API
 */
public static function allowedDomains()
{
    return [
        // '*',                        // star allows all domains
        'http://test1.example.com',
        'http://test2.example.com',
    ];
}

/**
 * @inheritdoc
 */
public function behaviors()
{
    return array_merge(parent::behaviors(), [

        // For cross-domain AJAX request
        'corsFilter'  => [
            'class' => \yii\filters\Cors::className(),
            'cors'  => [
                // restrict access to domains:
                'Origin'                           => static::allowedDomains(),
                'Access-Control-Request-Method'    => ['POST'],
                'Access-Control-Allow-Credentials' => true,
                'Access-Control-Max-Age'           => 3600,                 // Cache (seconds)
            ],
        ],

    ]);
}

This code will add to response special http-headers. Request http header should haves Origin (it will be added by browser automatically at Crossdomain AJAX). Response http headers should have Access-Control-* headers.

NOTE: If you don't see these http headers in response, probably it means that \yii\filters\Cors don't works. Check other behaviors/filters in controller. Try to disable CSRF validation for this controller (it may prevent external access):

/**
 * Controller for API methods.
 */
class ApiController extends Controller
{

    /**
     * @var bool See details {@link \yii\web\Controller::$enableCsrfValidation}.
     */
    public $enableCsrfValidation = false;

    // ...
}

UPD: Additionally should be checked your web-server. Probably nginx may require additional configuration, apache can require restarting.

UPD2: More complete instruction here: https://stackoverflow.com/a/42435695/3793592

Share:
17,255

Related videos on Youtube

echo_salik
Author by

echo_salik

Twitter | Facebook

Updated on September 23, 2022

Comments

  • echo_salik
    echo_salik over 1 year

    I am working with a pre-built API (not restfull) on Yii2 Framework. It responds with JSON data and accepts requests depending on User type and credential token. Now I have to make an app that is on a different location (domain) which is causing CORS conflict.

    My app is jQuery and I'm using $.ajax for data sending and receiving. How can I avoid this CORS conflict and use the API over ajax?

    Regards

    UPDATE:

    As IStranger told me in his answer I added the following code:

    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['corsFilter'] = [
            'class' => \yii\filters\Cors::className(),
            'cors' => [
                'Origin'                           => "*",
                'Access-Control-Request-Method'    => ['POST', 'GET'],
                'Access-Control-Allow-Credentials' => true,
                'Access-Control-Max-Age'           => 3600,
            ],
        ];
        return $behaviors;
    }
    

    But I am still getting the error. There is a beforeAction in the code can that be a problem?

    This is the RAW HEADER

    Request:

    Host: domain.com
    User-Agent: Mozilla/5.0 (Windows NT 10.0; WOW64; rv:48.0) Gecko/20100101 Firefox/48.0
    Accept: */*
    Accept-Language: en-US,en;q=0.5
    Accept-Encoding: gzip, deflate
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Referer: http://localhost/main/main.html
    Content-Length: 296
    Origin: http://localhost
    Connection: keep-alive
    

    Response:

    Cache-Control: no-store, no-cache, must-revalidate, post-check=0, pre-check=0
    Connection: Keep-Alive
    Content-Length: 101
    Content-Type: application/json; charset=UTF-8
    Date: Thu, 22 Sep 2016 17:23:48 GMT
    Expires: Thu, 19 Nov 1981 08:52:00 GMT
    Keep-Alive: timeout=5, max=100
    Pragma: no-cache
    Server: Apache/2.4.17 (Win64) PHP/5.6.16
    Set-Cookie: PHPSESSID=ph0b322gbq65m1f3m8fp9fphc0; path=/; HttpOnly
    X-Powered-By: PHP/5.6.16
    
  • echo_salik
    echo_salik over 7 years
    I am editing my question regarding your answer please see.
  • echo_salik
    echo_salik over 7 years
    I restarted Apache and it worked. I guess apache's cache or something made the problem persist.