Yii2:前端和API之间的同时身份验证

时间:2018-10-22 06:14:11

标签: php yii2 yii2-advanced-app

我已经将后端变成了API。而且API控制器具有HttpBasicAuth类型身份验证。

问题在于,即使在前端进行身份验证之后,只要向API发出请求,身份验证窗口就会出现。

我该怎么做,以便当用户在前端进行身份验证时,在向API发出请求时,不再要求用户访问密码和用户名?

API中的控制器示例:

class CategoryController extends ActiveController
{
    public $modelClass = 'api\models\Category';

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

        $behaviors['authenticator'] = [
            'class' => CompositeAuth::className(),
            'authMethods' => [
                [
                    'class' => HttpBasicAuth::className(),
                    'auth' => function($username, $password) {
                        $out = null;
                        $user = \common\models\User::findByUsername($username);
                        if ($user != null) {
                            if ($user->validatePassword($password)) $out = $user;
                        }
                        return $out;
                    }
                ],
            ],
        ];
        return $behaviors;
    }
}

2 个答案:

答案 0 :(得分:2)

这称为共享会话。这还取决于您的分层应用程序(前端和api)是否都在同一域中。如果是这样,请按照以下步骤配置前端和api设置(<app>/frontend/config/main.php<app>/api/config/main.php):

'components' => [
    ...
    'request' => [
        'csrfParam' => '_csrf-shared',
    ],
    ...
    'user' => [
        'identityClass' => 'common\models\User',
        'enableAutoLogin' => true,
        'identityCookie' => ['name' => '_identity-shared', 'httpOnly' => true],
    ],
    ...
    'session' => [
        'name' => 'advanced-shared',
    ],
    ...

这意味着您以相同的名称保存cookie和会话,以便当您登录前端并转到backend / api时,后端将获取相同的cookie,因此您将被检测为经过身份验证的用户。

这里有一个重要说明,为了使enableAutoLogin在两个级别上均有效,您应该为两个cookieValidationKey设置相同的main-local.php。您可以手动设置它们,或编辑init.php文件为所有层生成一个cookieValidationKey。 (只需确保您知道自己在做什么)。

顺便说一句,我认为在frontendapi之间进行同时认证不是一个好主意。如果是frontendbackend,那么它仍然可以忍受,但是api的交互作用与frontend有所不同。
我建议使用诸如Authorization: Bearer <token>之类的标题。您可以在Yii2 Rest Authentication

处获取更多信息。

更新

我认为这就是您所需要的。在ApiAuth文件夹中创建一个类,即common/components并粘贴以下代码:

<?php

namespace common\components;

use yii\filters\auth\HttpBasicAuth;

class ApiAuth extends HttpBasicAuth
{
    /**
     * @inheritdoc
     */
    public function authenticate($user, $request, $response)
    {
        if ($user->identity) {
            return $user->identity;
        }

        return parent::authenticate($user, $request, $response);
    }
}

此类从yii\filters\auth\HttpBasicAuth扩展。在调用浏览器提示之前,它会检查是否填充了user->dentity。如果是这样,则不需要promt。

在Controller行为中,将HttpBasicAuth替换为ApiAuth类:

use common\components\ApiAuth;
...
'authMethods' => [
    [
        'class' => ApiAuth::className(),
        'auth' => function($username, $password) {
        ...

答案 1 :(得分:0)

由于用户已经通过身份验证,因此我只需为连接的用户设置“ AccessControl”。如果他们没有连接,他们将收到代码403而不是401。

这可以解决问题:

class CategoryController extends ActiveController
{
    public $modelClass = 'api\models\Category';

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

        $behaviors['access'] = [
            'class' => \yii\filters\AccessControl::className(),
            'rules' => [
                [
                    'allow' => true,
                    'roles' => ['@'],
                ],
            ],
        ];

        return $behaviors;
    }
}