Yii2 cors 过滤错误,即不存在“Access-Control-Allow-Origin"标头

2022-01-07 00:00:00 php yii2 yii2-advanced-app angular

在这个问题之后,我将我的休息控制器行为设置为

Following This question i have set my rest controller behaviour as

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

    $auth= $behaviors['authenticator'] = [
        'class' => HttpBearerAuth::className(),
        'only' => ['dashboard'],
    ];
    $behaviors['contentNegotiator'] = [
        'class' => ContentNegotiator::className(),
        'formats' => [
            'application/json' => Response::FORMAT_JSON,
        ],
    ];
    $acces=$behaviors['access'] = [
        'class' => AccessControl::className(),
        'only' => ['login'],
        'rules' => [
            [
                'actions' => ['login'],
                'allow' => true,
                'roles' => ['?'],
            ],
        ],
    ];

    unset($behaviors['authenticator']);
    unset($behaviors['access']);

现在是 cors 过滤器

And now the cors filters

    // add CORS filter
    $behaviors['corsFilter'] = [
        'class' => yiifiltersCors::className(),
          'cors' => [
        // restrict access to
        'Access-Control-Allow-Origin' => ['*'],
        'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
        // Allow only POST and PUT methods
        'Access-Control-Request-Headers' => ['*'],
        // Allow only headers 'X-Wsse'
        'Access-Control-Allow-Credentials' => true,
        // Allow OPTIONS caching
        'Access-Control-Max-Age' => 86400,
        // Allow the X-Pagination-Current-Page header to be exposed to the browser.
        'Access-Control-Expose-Headers' => [],
      ]
    ];

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

我的 angular2 前端

An my angular2 frontend as

    const body = JSON.stringify(user);
let headers = new Headers();
headers.append('Content-Type', 'application/x-www-form-urlencoded');
headers.append('Content-Type', 'application/json');
headers.append('Access-Control-Allow-Credentials', "*");
return this._http.post(this.loginUrl, body, { headers:headers })
  .map((response: Response) => {
     //process response
  })
.catch(this.handleError);

但我仍然收到错误

Response to preflight request doesn't pass access control check: No
 'Access-Control-Allow-Origin' header is present on the requested resource. Origin 
 'http://localhost:3000' is therefore not allowed access.

因为我在 yii2 行为未设置身份验证器中设置了 cors 过滤器并稍后添加它,所以可能有什么问题我会错过什么

What could be wrong since ive set the cors filter in yii2 behaviours unset authenticator and added it later What could i be missing out

我还检查了 此链接以及这个但没有一个能解决问题

I have also checked on This link and also this one but none solves the issue

推荐答案

如果 CORS 标头有任何问题,我建议使用以下说明:

In case of any problems with CORS headers, I recommend to use following instruction:

  1. 将 cors 配置添加到您的控制器.例如:

  1. Add cors configuration to your controller. For instance:

/**
 * 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' => yiifiltersCors::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)
            ],
        ],

    ]);
}

  • 上面的代码将添加响应特殊的http-headers.使用浏览器调试工具检查 http 标头:

  • The above code will add to response special http-headers. Check http-headers using browser debug tools:

    请求 http 标头 应包含 Origin.它将在跨域 AJAX 中由浏览器自动添加.这个 http-header 也可以通过你的 JS 库添加.没有这个 http-header corsFilter 将无法工作.

    Request http header should contain Origin. It will be added by browser automatically at Crossdomain AJAX. This http-header can be added also via your JS library. Without this http-header corsFilter won't work.

    POST /api/some-method-name HTTP/1.1
    Host: api.example.com
    Connection: keep-alive
    Content-Length: 86
    Accept: */*
    Origin: https://my-site.example.com
    User-Agent: Mozilla/5.0 (X11; Linux x86_64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/56.0.2924.87 Safari/537.36
    Content-Type: application/x-www-form-urlencoded; charset=UTF-8
    Referer: https://my-site.example.com/
    Accept-Encoding: gzip, deflate, br
    Accept-Language: en-GB,en;q=0.8,en-US;q=0.6,ru;q=0.4
    

  • 响应 http 标头 应包含 Access-Control-* 标头.这个 http 头将由 corsFilter 添加.

  • Response http headers should contain Access-Control-* headers. This http-header will be added by corsFilter.

    HTTP/1.1 200 OK
    Access-Control-Allow-Credentials: true
    Access-Control-Allow-Origin: https://my-site.example.com
    Content-Type: application/json; charset=UTF-8
    Date: Fri, 24 Feb 2017 09:21:47 GMT
    Server: Apache
    Content-Length: 27
    Connection: keep-alive
    

  • 如果您没有看到这些 http 标头 响应,可能意味着 yiifiltersCors 不起作用或与其他过滤器.

  • If you don't see these http headers in response, probably it means that yiifiltersCors doesn't work or conflicts with other filters.

    检查控制器中的其他行为/过滤器.尝试添加 corsFilter 作为第一行为.可能其他一些行为阻止了 corsFilter 的执行.

    Check other behaviors/filters in controller. Try add corsFilter as first behavior. Probably some other behaviors prevents execution of corsFilter.

    尝试禁用此控制器的 CSRF 验证(这可能会阻止外部访问):

    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 yiiwebController::$enableCsrfValidation}.
         */
        public $enableCsrfValidation = false;
    
        // ...
    }
    

  • 如果您使用 authenticator 过滤器(例如,您的控制器扩展了 yiiestActiveController),则必须在 应用之前应用 CORS 过滤器身份验证方法.此外,还必须为 CORS 预检请求禁用身份验证,以便浏览器可以安全地确定是否可以预先发出请求,而无需发送身份验证凭据.

  • If you are using authenticator filter (for example, your controller extends yiiestActiveController) the CORS filter has to be applied BEFORE authentication methods. Also authentication has to be disabled for the CORS Preflight requests so that a browser can safely determine whether a request can be made beforehand without the need for sending authentication credentials.

    use yiifiltersauthHttpBasicAuth;
    
    public function behaviors()
    {
        $behaviors = parent::behaviors();
    
        // remove authentication filter
        $auth = $behaviors['authenticator'];
        unset($behaviors['authenticator']);
    
        // add CORS filter
        $behaviors['corsFilter'] = [
            'class' => yiifiltersCors::className(),
        ];
    
        // re-add authentication filter
        $behaviors['authenticator'] = $auth;
        // avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
        $behaviors['authenticator']['except'] = ['options'];
    
        return $behaviors;
    }
    

  • 另外应该检查您的网络服务器.可能 nginx 可能需要额外配置,apache 可能需要重启.

    Access-Control-* 响应头可以使用 web-server 添加(参见 apache 和 nginx).但我不建议使用这种方式,因为在这种情况下,您无法使用 application.properties 管理 http-haders.

    Access-Control-* headers in response can be added using web-server (see for apache and nginx). But I don't recommend to use this way, because in this case you can't manage http-haders using application.

    一些有用的信息可以在这里找到:

    Some useful information can be found here:

    • Yii2:如何在非RESTful API
  • 相关文章