php Yii 2 cors过滤器错误,不存在“Access-Control-Allow-Origin”标头

cqoc49vn  于 2023-05-05  发布在  PHP
关注(0)|答案(6)|浏览(126)

This question之后,我将rest控制器行为设置为

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过滤器

// add CORS filter
    $behaviors['corsFilter'] = [
        'class' => \yii\filters\Cors::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前端

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过滤器后,会有什么问题呢?
我还检查了This linkthis one,但没有解决问题

4dc9hkyq

4dc9hkyq1#

如果CORS头出现任何问题,我建议使用以下指令:
1.将cors配置添加到您的控制器。例如:

/**
 * 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)
            ],
        ],

    ]);
}

1.上面的代码会给response**添加特殊的http-headers。使用浏览器调试工具检查http-headers:
1.请求http头必须包含Origin。它将由浏览器自动添加在跨域 AJAX 。这个http-header也可以通过你的JS库添加。如果没有这个http-header,corsFilter将无法工作。

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

1.响应http header应该包含Access-Control-* header。这个HTTP头将由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

1.如果你在响应中没有看到这些http头,可能意味着\yii\filters\Cors不工作或与其他过滤器冲突。
1.检查控制器中的其他行为/过滤器。尝试添加corsFilter作为
第一个行为**。可能是其他一些行为阻止了corsFilter的执行。
1.尝试禁用此控制器的CSRF验证(可能会阻止外部访问):

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

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

    // ...
}

1.如果您使用authenticatorfilter(例如,您的控制器扩展了yii\rest\ActiveController),则必须在验证方法之前应用CORS filter。此外,必须对CORS Preflight请求禁用身份验证,以便浏览器可以安全地确定是否可以预先发出请求,而无需发送身份验证凭据。

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;
}

1.此外,还应检查您的Web服务器。可能nginx需要额外配置,apache可能需要重启
1.响应中的Access-Control-*标头可以使用web服务器添加(有关apachenginx,请参见)。但我不建议使用这种方式,因为在这种情况下,您无法使用应用程序管理http-haders。

hm2xizp9

hm2xizp92#

试试这个:

public static function allowedDomains()
{
    return [
        // '*',                        // star allows all domains
        'http://localhost:3000',
        'http://test2.example.com',
    ];
}  


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)

                ],
            ],

        ]);
    }

在您的控制器上添加此功能。
而One Thing angular2在第一次使用OPTION方法,因此也允许OPTION方法

brccelvz

brccelvz3#

当前端在默认端口(80)以外的端口上运行时,就会出现问题。
然后在yii中你需要指定工作的端口。示例:前端在Yii cors set中运行http: // localhost: 3000

'Origin' => ['http: // localhost: 3000']

如果你没有指定端口(3000),Yii默认解释端口,结果是:

'Origin' => ['http: // localhost: 80']
ykejflvf

ykejflvf4#

最后,我有答案,可能是一个傻瓜证明一个,虽然这里回答的大多数事情都是好的,但没有什么对我有用,除非我真的明白这个问题正在发生什么。
正如一些人正确地说,浏览器往往发送选项在飞行前,所以要确保你的每个控制器,如果定制能够处理选项请求,如果不是你会像我一样徘徊年龄,有什么错,我已经配置了一切就像在文档中描述的,实现一切都是大家在网上说.
我只是在这里给你几个例子,希望这将有助于实现上述所有的解决方案后仍然没有工作,除非我添加了一个特定的功能,我的控制器actionOptions,像下面这样的东西

public function actionOptions() {
    $header = header('Access-Control-Allow-Origin: *');
}

和修改的行为简单地描述在Yii文档

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

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

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

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

    return $behaviors;
}

这在我的chrome浏览器上工作得很好。
现在,如果你有一些custome路线设置,就像我为我的一个控制器
示例:
GET v1/users/profile您必须将另一个路由也设置为OPTIONS v1/users/profile。
最后但并非最不重要的一点是,在某些情况下,您的某个操作可能会被进一步定制,或者只是使用标准操作,例如我的actionIndex
我添加了标题,具体如下在顶部的行动,就像下面的行动索引

public function actionProfile() {
    $header = header('Access-Control-Allow-Origin: *');
    $profile = new \app\modules\v1\models\Profile();
    return $profile->prepare();
}

  public function actionIndex() {
    $header = header('Access-Control-Allow-Origin: *');
    $profile = new \app\modules\v1\models\Profile();
    return $profile->prepare();
}

我希望这会对你们中的一些人有所帮助:)。

4xrmg8kj

4xrmg8kj5#

写$behaviors ['access'] ie很重要。AccessControl作为最后一个参数,例如:

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

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

    $behaviors['corsFilter'] = [     
        'class' => \yii\filters\Cors::class,
        'cors'  => [
                'Origin' => ['*'], 
                'Access-Control-Request-Method'    => ['POST', 'GET', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'], 
                'Access-Control-Allow-Headers' => ['Origin', 'X-Requested-With', 'Content-Type', 'accept', 'Authorization'], 
                'Access-Control-Request-Headers' => ['*'],    
                'Access-Control-Max-Age'           => 3600, // Cache (seconds) 
                // Allow the X-Pagination-Current-Page header to be exposed to the browser.             
                'Access-Control-Expose-Headers' => ['X-Pagination-Total-Count', 'X-Pagination-Page-Count', 'X-Pagination-Current-Page', 'X-Pagination-Per-Page'] 
        ] 
    ];           

    $behaviors['authenticator'] = [ ... whatever ... ];          

    $behaviors['access'] = [           
      'class' => AccessControl::className(),           
      'rules' => [   
                  [  
                    'allow' => true,   
                    'actions' => ['options'], // important for cors ie. pre-flight requests   
                  ], 
                ]   
    ];
  }
yyhrrdl8

yyhrrdl86#

我的解决方法是:

// add CORS filter
    $behaviors['corsFilter'] = [
        'class' => Cors::class,
    ];

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

我也有配置为:在UrlManger中提到控制器名称

'urlManager' => [
        'enablePrettyUrl' => true,
        // 'enableStrictParsing' => true,
        'showScriptName' => false,

        'rules' => [
            [
                'class' => 'yii\rest\UrlRule',
                'pluralize' => false,
                'controller' => [
                    'v1/setting',
                    'v1/restaurant',
                                       ],
                'ruleConfig' => [
                    'class' => 'yii\web\UrlRule',
                ],
            ],
            'v1/<controller:\w+>/<id:\d+>' => 'v1/<controller>/view',
            'v1/<controller:\w+>/<action:\w+>/<id:\d+>' => 'v1/<controller>/<action>',
            'v1/<controller:\w+>/<action:\w+>' => 'v1/<controller>/<action>',
            'v1/<controller:[\w\-]+>/<id:\d+>' => 'v1/<controller>/view',
            'v1/<controller:[\w\-]+>/<action:\w+>/<id:\d+>' => 'v1/<controller>/<action>',
            'v1/<controller:[\w\-]+>/<action:\w+>' => 'v1/<controller>/<action>',
        ],
    ],

相关问题