Yii2 REST + Angular Cross Domain CORS

Ari*_*jay 6 rest yii-components angularjs yii2 yii2-advanced-app

我开发了Angular和Yii2 REST服务.在跨域有问题.下面添加我的angular&Yii2 REST代码.

AngularJs:(像' http://organization1.example.com ', ' http://organization2.example.com ',....)

$http.defaults.useXDomain = true;
$http.defaults.withCredentials = true;
$http.defaults.headers.common['Authorization'] = 'Bearer ' + MYTOKEN
Run Code Online (Sandbox Code Playgroud)

我来自Angular Controller的请求:

apiURL = 'http://api.example.com';
$http.get(apiURL + '/roles')
     .success(function (roles) { })
     .error(function () { });
Run Code Online (Sandbox Code Playgroud)

Yii2 .htaccess :( REST网址如' http://api.example.com ')

Header always set Access-Control-Allow-Origin: "*"
Header always set Access-Control-Allow-Credentials: true
Header always set Access-Control-Allow-Methods "POST, GET, PUT, DELETE, OPTIONS"
Header always set Access-Control-Allow-Headers "Authorization,X-Requested-With, content-type"
Run Code Online (Sandbox Code Playgroud)

Yii2我的行为:

public function behaviors() {
    $behaviors = parent::behaviors();
    $behaviors['corsFilter'] = [
        'class' => Cors::className(),
        'cors' => [
            'Origin' => ['*'],
            'Access-Control-Expose-Headers' => [
                'X-Pagination-Per-Page',
                'X-Pagination-Total-Count',
                'X-Pagination-Current-Page',
                'X-Pagination-Page-Count',
            ],
        ],
    ];
    $behaviors['authenticator'] = [
        'class' => HttpBearerAuth::className(),
        'except' => ['options'],
    ];
    $behaviors['contentNegotiator'] = [
        'class' => ContentNegotiator::className(),
        'formats' => [
            'application/json' => Response::FORMAT_JSON,
        ],
    ];

    return $behaviors;
}
Run Code Online (Sandbox Code Playgroud)

问题

从我的角度请求是'GET'方法,但它将进入'OPTIONS'方法并返回401 Unauthorized error(CORS).因为请求Authorization标头不发送.

Sal*_*ani 9

更新:

正如@jlapoutre所指出的,现在官方文档中对此进行了详细描述:

将交叉源资源共享过滤器添加到控制器比添加上述其他过滤器要复杂一些,因为必须在认证方法之前应用CORS过滤器,因此与其他过滤器相比需要稍微不同的方法.此外,还必须为CORS预检请求禁用身份验证,以便浏览器可以安全地确定是否可以事先进行请求,而无需发送身份验证凭据.下面显示了将yii\filters\Cors过滤器添加到从yii\rest\ActiveController扩展的现有控制器所需的代码:

use yii\filters\auth\HttpBasicAuth;

public function behaviors()
{
    $behaviors = parent::behaviors();

    // remove authentication filter
    $auth = $behaviors['authenticator'];
    unset($behaviors['authenticator']);

    // add CORS filter
    $behaviors['corsFilter'] = [
        'class' => \yii\filters\Cors::className(),
    ];

    // re-add authentication filter
    $behaviors['authenticator'] = $auth;
    // avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
    $behaviors['authenticator']['except'] = ['options'];

    return $behaviors;
}
Run Code Online (Sandbox Code Playgroud)

旧答案 (已弃用)

合并时存在排序问题parent::behaviors().详情请点击此处.

我建议在与父数组合并时不要定义键:

public function behaviors()
{
    return \yii\helpers\ArrayHelper::merge([
        [
            'class' => \yii\filters\Cors::className(),
            'cors' => [...],
        ],
        [
            'class' => \yii\filters\auth\HttpBearerAuth::className(),
            'except' => ['options'],
        ],
        [
            'class' => ContentNegotiator::className(),
            'formats' => [...],
        ]
    ], parent::behaviors());
}
Run Code Online (Sandbox Code Playgroud)

  • 现在可以在以下位置清楚地记录下来:http://www.yiiframework.com/doc-2.0/guide-rest-controllers.html#cors-只需遵循本指南即可使用。摘要:确保身份验证是在CORS行为之后进行的,并且始终将身份验证排除在选项之外。 (2认同)

Ser*_*nko 1

在你的控制器中:

use yii\filters\Cors;
...
public function behaviors()
{
    return array_merge([
        'cors' => [
            'class' => Cors::className(),
            #special rules for particular action
            'actions' => [
                'your-action-name' => [
                    #web-servers which you alllow cross-domain access
                    'Origin' => ['*'],
                    'Access-Control-Request-Method' => ['POST'],
                    'Access-Control-Request-Headers' => ['*'],
                    'Access-Control-Allow-Credentials' => null,
                    'Access-Control-Max-Age' => 86400,
                    'Access-Control-Expose-Headers' => [],
                ]
            ],
            #common rules
            'cors' => [
                'Origin' => [],
                'Access-Control-Request-Method' => [],
                'Access-Control-Request-Headers' => [],
                'Access-Control-Allow-Credentials' => null,
                'Access-Control-Max-Age' => 0,
                'Access-Control-Expose-Headers' => [],
            ]
        ],
    ], parent::behaviors());
}
Run Code Online (Sandbox Code Playgroud)

文档