Yii2:前端和 API 之间的同时认证
Yii2: Simultaneous authentication between frontend and API
我已经将后端变成了 API。 API 控制器具有 HttpBasicAuth 类型的身份验证。
问题是,即使在前端进行身份验证后,每当向 API 发出请求时,都会出现身份验证 window。
当用户在前端进行身份验证时,在向 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;
}
}
这叫分享session。它还取决于您的层应用程序(前端和 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',
],
...
意思是你保存的cookies和session同名,这样当你在前端登录,然后去backend/api,后端获取相同的cookies,所以你会检测为经过身份验证的用户。
这里有一个重要提示,为了 enableAutoLogin
对两层都起作用,您应该为两个 main-local.php
设置设置相同的 cookieValidationKey
。您可以手动设置它们,或编辑 init.php
文件为所有层生成一个 cookieValidationKey。 (只要确保你知道自己在做什么)。
顺便说一句,我认为在frontend
和api
之间同时进行身份验证不是一个好主意。如果是 frontend
和 backend
那么它仍然可以忍受,但是 api
交互与 frontend
相比是不同的。
我建议像 Authorization: Bearer <token>
一样使用 headers。您可以在此处获得更多信息 Yii2 Rest Authentication
更新
我想这就是你需要的。在 common/components
文件夹中创建一个 class,即 ApiAuth
并粘贴以下代码:
<?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);
}
}
此 class 从 yii\filters\auth\HttpBasicAuth
扩展而来。在调用浏览器提示之前,它会检查 user->dentity
是否已填充。如果是这样,则不需要提示。
在您的控制器行为中,将 HttpBasicAuth
替换为 ApiAuth
class:
use common\components\ApiAuth;
...
'authMethods' => [
[
'class' => ApiAuth::className(),
'auth' => function($username, $password) {
...
因为用户已经通过身份验证,所以我只为连接的用户设置 "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;
}
}
我已经将后端变成了 API。 API 控制器具有 HttpBasicAuth 类型的身份验证。
问题是,即使在前端进行身份验证后,每当向 API 发出请求时,都会出现身份验证 window。
当用户在前端进行身份验证时,在向 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;
}
}
这叫分享session。它还取决于您的层应用程序(前端和 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',
],
...
意思是你保存的cookies和session同名,这样当你在前端登录,然后去backend/api,后端获取相同的cookies,所以你会检测为经过身份验证的用户。
这里有一个重要提示,为了 enableAutoLogin
对两层都起作用,您应该为两个 main-local.php
设置设置相同的 cookieValidationKey
。您可以手动设置它们,或编辑 init.php
文件为所有层生成一个 cookieValidationKey。 (只要确保你知道自己在做什么)。
顺便说一句,我认为在frontend
和api
之间同时进行身份验证不是一个好主意。如果是 frontend
和 backend
那么它仍然可以忍受,但是 api
交互与 frontend
相比是不同的。
我建议像 Authorization: Bearer <token>
一样使用 headers。您可以在此处获得更多信息 Yii2 Rest Authentication
更新
我想这就是你需要的。在 common/components
文件夹中创建一个 class,即 ApiAuth
并粘贴以下代码:
<?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);
}
}
此 class 从 yii\filters\auth\HttpBasicAuth
扩展而来。在调用浏览器提示之前,它会检查 user->dentity
是否已填充。如果是这样,则不需要提示。
在您的控制器行为中,将 HttpBasicAuth
替换为 ApiAuth
class:
use common\components\ApiAuth;
...
'authMethods' => [
[
'class' => ApiAuth::className(),
'auth' => function($username, $password) {
...
因为用户已经通过身份验证,所以我只为连接的用户设置 "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;
}
}