Yii2 + restapi + cors + bearer - 在创建自定义控制器操作时未经授权

时间:2017-03-17 09:11:54

标签: rest yii2 cors

我正在制作角度2 / Yii2 app

当我从带有承载标题的邮递员调用自定义控制器/操作时,一切正常,但是当我使用角度2应用程序(localhost:4200)中的相同标头调用它时,我总是得到未经授权的401错误。 当我执行标准操作时,例如来自guide的示例,如:

GET /users: list all users page by page;
POST /users: create a new user;

一切正常,只有在我创建自定义操作时,才会被我未经授权。

这是跨域应用程序, angular可在web.example.com上找到, yii2 app在srv.example.com上

namespace app\controllers\restapi;

use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBearerAuth;

class SearchOrderController extends \yii\rest\Controller
{
    public $modelClass = 'app\models\Order';
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $auth = $behaviors['authenticator'];
        unset($behaviors['authenticator']);
        $behaviors['corsFilter'] = [
                'class' => \yii\filters\Cors::className(),
        ];
        $behaviors['authenticator'] = [
                'class' => CompositeAuth::className(),
                'authMethods' => [
                        HttpBearerAuth::className(),
                ],
        ];
        // avoid authentication on CORS-pre-flight requests (HTTP OPTIONS method)
        return $behaviors;
    }
    public function actionSearch(){
        \Yii::$app->response->format=\yii\web\Response::FORMAT_JSON;
        return ['index'=>'some text', 'value'=>123];
    }
}

我的网址管理员:

        [
            'class' => 'yii\rest\UrlRule',
            'controller' => 'order',
            'pluralize' => false,
            'extraPatterns' => [
                'GET order/<id:\id+>' => 'order/view',
            ]
        ],
        [
            'class' => 'yii\rest\UrlRule',
            'controller' => 'search-order',
            'pluralize' => false,
            'extraPatterns' => [
                'GET search-order/search' => 'search-order/search',
        ]

2 个答案:

答案 0 :(得分:0)

我使用此处发布的解决方案解决了我的问题:

Yii2 Rest - Custom action and OPTIONS method

并实现自定义Cors类:

<?php 
namespace app\components;

use Yii;
use yii\filters\Cors;

class CustomCors extends  Cors

{
    public function beforeAction($action)
    {
        parent::beforeAction($action);

        if (Yii::$app->getRequest()->getMethod() === 'OPTIONS') {
            Yii::$app->getResponse()->getHeaders()->set('Allow', 'POST GET PUT');
            Yii::$app->end();
        }

        return true;
    }
}

并相应地更改我的控制器行为:

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

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

        // add CORS filter
        $behaviors['corsFilter'] = [
                'class' =>CustomCors::className()
        ];

        // re-add authentication filter
        $behaviors['authenticator'] = [
                'class' => CompositeAuth::className(),
                'authMethods' => [
                        HttpBearerAuth::className(),
                ],

        ];

        return $behaviors;
   }

答案 1 :(得分:0)

看起来这是一个preflight request问题。我在这里看到两件事要解决。

首先,您需要在扩展yii\rest\Controller时实施响应该请求的操作。这样的动作is already implemented by Yii但在其子控制器yii\rest\ActiveController中。因此,要么使用actions()函数来导入它,就像它已完成here一样,或者您可以直接实现它,就像在其他satck溢出帖子中一样:

Post Request working in Postman but returns Preflight error in Angular 2 app

然后您需要定义相关规则:

[
    'class' => 'yii\rest\UrlRule',
    'controller' => 'order',
    'pluralize' => false,
    'extraPatterns' => [
        'GET order/<id:\id+>' => 'order/view',
        'OPTIONS order/<id:\id+>' => 'order/options',
    ]
],
[
    'class' => 'yii\rest\UrlRule',
    'controller' => 'search-order',
    'pluralize' => false,
    'extraPatterns' => [
        'GET search-order/search' => 'search-order/search',
        'OPTIONS search-order/search' => 'search-order/options',
]

接下来,您需要让您的身份验证允许预检请求,因为浏览器不会发送任何令牌。通过添加此行,如official docs

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