简体   繁体   English

Yii2 CORS with Auth 不适用于非 CRUD 操作

[英]Yii2 CORS with Auth not working for non CRUD actions

I am building an API in Yii2 and have added CORS and authentication.我正在 Yii2 中构建 API 并添加了 CORS 和身份验证。 This works fine for all Create/Read/Update/Delete actions but not for custom actions.这适用于所有创建/读取/更新/删除操作,但不适用于自定义操作。 Has anyone experienced this before?有没有人经历过这种情况?

URL manager:网址管理器:

['class' => 'yii\rest\UrlRule', 'controller' => 'api/v1/user', 'pluralize' => false],

Controller behaviors:控制器行为:

public function behaviors()
{
    return ArrayHelper::merge([
            'corsFilter' => [
                'class' => Cors::className(),
            ],
            [
                'class' => HttpBearerAuth::className(),
                'except' => ['options',
                             'login',
                ],
            ],
        ], parent::behaviors()
    );
}

As mentioned, actions for CRUD are fine but a custom action such as http://domain.com/user/test will respond with a 401 Unauthorised response.如前所述,CRUD 的操作很好,但是诸如http://domain.com/user/test类的自定义操作将以401 Unauthorised响应进行响应。

Is it not possible to get CORS and auth to work together on custom actions?是否无法让 CORS 和 auth 在自定义操作上协同工作?

Edit: I should add that the issue (401) occurs only when a browser makes the OPTIONS request.编辑:我应该补充一点,仅当浏览器发出OPTIONS请求时才会出现问题 (401)。 Normal requests (curl,Postman) are not affected.正常请求(curl、Postman)不受影响。 The issue seems to occur with the RESTful,Cors,Auth combination.问题似乎发生在 RESTful、Cors、Auth 组合中。

try this:试试这个:

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

    unset($behaviors['authenticator']);

    $behaviors['corsFilter'] = [
        'class' => Cors::className(),
        'cors' => [
            'Origin' => ['*'],
            'Access-Control-Request-Method' => ['GET', 'POST', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
            'Access-Control-Request-Headers' => ['*'],
            'Access-Control-Allow-Credentials' => true,
        ],
    ];

    $behaviors['authenticator'] = [
        'class' =>  HttpBearerAuth::className(),
        'except' => ['options','login'],
    ];

    return $behaviors;
}

It will unset the default authenticator implemented by the parent controller to be sure that cors is treated first.它将取消设置父控制器实现的默认authenticator ,以确保cors处理cors Then we force cors to allow credentials before implementing your own authenticator .然后我们强制cors在实现您自己的authenticator之前允许凭据。


The other thing that may raise that Unauthorized error is a not-found or wrong Options response as a browser request it first to get a list of allowed verbs.另一个可能引发Unauthorized错误的事情是未找到或错误的Options响应,因为浏览器首先请求它获取允许的动词列表。 You may check that list in its headers response within your browser's network tab.您可以在浏览器的网络选项卡中的标头响应中检查该列表。

The general rule is when you ask your browser to perform a sensible verb like PUT, DELETE or POST to any url it may first send an OPTIONS request to that same url ( check this ) to check if that verb is allowed before sending the real request.一般规则是,当您要求浏览器对任何url执行诸如 PUT、DELETE 或 POST 之类的明智动词时,它可能会首先向同一个url发送 OPTIONS 请求(检查)以在发送真实请求之前检查该动词是否被允许. So Yii should be configured to respond to all those OPTIONS verbs by performing the correct redirections.所以 Yii 应该被配置为通过执行正确的重定向来响应所有这些 OPTIONS 动词。

The default CRUD actions implemented by ActiveController are using those default patterns : ActiveController实现的默认 CRUD 操作使用这些默认模式

'PUT,PATCH {id}' => 'update',
'DELETE {id}' => 'delete',
'GET,HEAD {id}' => 'view',
'POST' => 'create',
'GET,HEAD' => 'index',
'{id}' => 'options',
'' => 'options',

So whatever configurations you did implement in urlManager['rules'] be sure to not override the last 2 of them and if you are using custom patterns always remember to include its equivalent options verbs like in this example:因此,无论您在urlManager['rules']实现了何种配置,请务必不要覆盖其中的最后 2 个,并且如果您使用自定义模式,请始终记住包含其等效的options动词,如本例所示:

[
    'class' => 'yii\rest\UrlRule', 
    'controller' => ['account' => 'auth/account'], 
    'patterns' => [
        'POST,HEAD login'  => 'login',
        'POST,HEAD signup' => 'signup',
        'POST req-reset-pass' => 'request-password-reset',
        'POST reset-pass' => 'reset-password',
        // OPTTIONS VERBS
        'OPTIONS login' => 'options',
        'OPTIONS signup' => 'options',
        'OPTIONS req-reset-pass' => 'options',
        'OPTIONS reset-pass' => 'options',
    ]
],

The same applies when adding custom patterns within extraPatterns .extraPatterns 中添加自定义模式时同样适用。


The Options action is implemented by default in ActiveController . Options操作默认在ActiveController it's code can be seen here .它的代码可以在这里看到。 In case you are extending a different controller than ActiveController like maybe \\yii\\rest\\Controller be sure to manually include it:如果你扩展了一个不同于ActiveController控制器,比如\\yii\\rest\\Controller一定要手动包含它:

public function actions() 
{
    $actions = parent::actions();
    $actions['options'] = [
        'class' => 'yii\rest\OptionsAction',
        // optional:
        'collectionOptions' => ['GET', 'POST', 'HEAD', 'OPTIONS'],
        'resourceOptions' => ['GET', 'PUT', 'PATCH', 'DELETE', 'HEAD', 'OPTIONS'],
    ];
    return $actions;
}

Just move your corsFilter block above the authenticator block like this:只需将您的 corsFilter 块移动到验证器块上方,如下所示:

public function behaviors()
    {
        return [
            'corsFilter' => [
                'class' => \yii\filters\Cors::className(),
            ],
            'authenticator' => [
                'class' => HttpBearerAuth::className(),
            ],
            'contentNegotiator' => [
                'class' => ContentNegotiator::className(),
                'formats' => [
                    'application/json' => Response::FORMAT_JSON,
                ],
            ],

        ];
    }

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM