Yii2 Rest Authentication Bearer Post 数据缺失
Yii2 Rest Authentication Bearer Post Data missing
我正在研究 REST API。因此我准备了一个函数,通过 curl 将身份验证数据发送到 REST 服务器。我已经实施了两个身份验证选项。第一个是基本身份验证,第二个是通过令牌(Bearer)进行身份验证。
现在,我遇到了麻烦,因为在 REST 服务器上,如果通过令牌进行身份验证,REST 服务器不会接收到 POST 数据。身份验证本身正在运行,但 POST 数据将丢失。如果通过基本身份验证进行身份验证,REST 服务器将接收 POST 数据,没问题。
private function request($postdata){
$url = $this->service_url_private;
$curl = curl_init($url);
$curl_post_data = $postdata;
// check if token authentication is used
if (array_key_exists('token', $postdata )){
$token = $postdata['token'];
$authorization = 'Authorization: Bearer ' . $token;
// prepare curl for Bearer Token Authorization
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization));
} else {
// otherwise use BASIC authentication
if (array_key_exists('email', $postdata )){
$username = $postdata['email'];
}
if (array_key_exists('password', $postdata )){
$password = $postdata['password'];
}
// prepare curl for Basic Authentication
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, "$username:$password");
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post_data);
curl_setopt($curl, CURLINFO_HEADER_OUT, true); // Detail information for debugging
curl_setopt($curl, CURLOPT_VERBOSE,true);
$curl_response = curl_exec($curl); // Detail information for debugging
$info = curl_getinfo($curl); // Detail information for debugging
curl_close($curl);
var_dump($info);
return $curl_response;
}
此外,$curl_post_data 在调试时由客户端显示所有数据,然后用 curl_exec($curl) 执行其余调用。
可能是什么问题?
经过很多小时后,我找到了问题所在以及该问题的解决方案。
问题是:
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization));
使用'Content-Type: application/json' 会导致丢失POST 数据信息。
解决方法是:
改变
'Content-Type: application/json'
到
'Content-Type: application/x-www-form-urlencoded'
您可以使用 yii2 的 HttpBasicAuth 身份验证器行为来进行不记名令牌身份验证。
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::className(),
];
return $behaviors;
}
对于您建议的解决方案,您应该使用 json 请求解析器。
'request' => [
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
]
使用以下代码创建新文件并将其保存在命名空间中。然后使用此文件代替 \yii\filters\auth\HttpBearerAuth.
<?php
namespace api\filters\auth;
use api\components\HttpResponseCode;
use yii\db\Exception;
use yii\web\UnauthorizedHttpException;
class HttpBearerAuth extends \yii\filters\auth\HttpBearerAuth {
/**
* @var string the HTTP authentication realm
*/
public $realm = 'api';
public $pattern = FALSE;
public function authenticate($user, $request, $response) {
$authHeader = $request->getHeaders()->get('Authorization');
// Following condition is added to support fastcgi issue.
if ($authHeader === null) {
$authHeader = $this->getBearerAuthFromSession();
$this->pattern = '/^Bearer\s+(.*?)$/';
}
if ($authHeader !== null) {
if ($this->pattern) {
preg_match($this->pattern, $authHeader, $matches);
$identity = $user->loginByAccessToken($matches[1], get_class($this));
} else {
$identity = $user->loginByAccessToken($authHeader, get_class($this));
}
if ($identity === null) {
return $this->handleFailure($response);
}
return $identity;
}
return null;
}
public function challenge($response) {
$response->getHeaders()->set('WWW-Authenticate', "Bearer realm=\"{$this->realm}\"");
}
public function handleFailure($response) {
$e = new UnauthorizedHttpException('Your request was made with invalid credentials.');
throw $e;
}
/**
* In HttpBearerAuth, some development environments do not populate Authorization header in the request;
* The issue is caused by CGI/FastCGI mode in Apache.
* Following lines must be added in api/web/.htaccess:
* # Authorization Headers
* RewriteCond %{HTTP:Authorization} .
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
*
* This function is used to access the following value in HttpBearerAuth to make it working :
* $_SERVER[‘REDIRECT_HTTP_AUTHORIZATION’].
* @return string|null
*/
public function getBearerAuthFromSession(): ?string {
if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] != "") {
return $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
}
return NULL;
}
}
我正在研究 REST API。因此我准备了一个函数,通过 curl 将身份验证数据发送到 REST 服务器。我已经实施了两个身份验证选项。第一个是基本身份验证,第二个是通过令牌(Bearer)进行身份验证。
现在,我遇到了麻烦,因为在 REST 服务器上,如果通过令牌进行身份验证,REST 服务器不会接收到 POST 数据。身份验证本身正在运行,但 POST 数据将丢失。如果通过基本身份验证进行身份验证,REST 服务器将接收 POST 数据,没问题。
private function request($postdata){
$url = $this->service_url_private;
$curl = curl_init($url);
$curl_post_data = $postdata;
// check if token authentication is used
if (array_key_exists('token', $postdata )){
$token = $postdata['token'];
$authorization = 'Authorization: Bearer ' . $token;
// prepare curl for Bearer Token Authorization
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization));
} else {
// otherwise use BASIC authentication
if (array_key_exists('email', $postdata )){
$username = $postdata['email'];
}
if (array_key_exists('password', $postdata )){
$password = $postdata['password'];
}
// prepare curl for Basic Authentication
curl_setopt($curl, CURLOPT_HTTPAUTH, CURLAUTH_BASIC);
curl_setopt($curl, CURLOPT_USERPWD, "$username:$password");
}
curl_setopt($curl, CURLOPT_RETURNTRANSFER, true);
curl_setopt($curl, CURLOPT_POST, true);
curl_setopt($curl, CURLOPT_POSTFIELDS, $curl_post_data);
curl_setopt($curl, CURLINFO_HEADER_OUT, true); // Detail information for debugging
curl_setopt($curl, CURLOPT_VERBOSE,true);
$curl_response = curl_exec($curl); // Detail information for debugging
$info = curl_getinfo($curl); // Detail information for debugging
curl_close($curl);
var_dump($info);
return $curl_response;
}
此外,$curl_post_data 在调试时由客户端显示所有数据,然后用 curl_exec($curl) 执行其余调用。
可能是什么问题?
经过很多小时后,我找到了问题所在以及该问题的解决方案。
问题是:
curl_setopt($curl, CURLOPT_HTTPHEADER, array('Content-Type: application/json' , $authorization));
使用'Content-Type: application/json' 会导致丢失POST 数据信息。
解决方法是:
改变
'Content-Type: application/json'
到
'Content-Type: application/x-www-form-urlencoded'
您可以使用 yii2 的 HttpBasicAuth 身份验证器行为来进行不记名令牌身份验证。
use yii\filters\auth\HttpBasicAuth;
public function behaviors()
{
$behaviors = parent::behaviors();
$behaviors['authenticator'] = [
'class' => HttpBasicAuth::className(),
];
return $behaviors;
}
对于您建议的解决方案,您应该使用 json 请求解析器。
'request' => [
'parsers' => [
'application/json' => 'yii\web\JsonParser',
]
]
使用以下代码创建新文件并将其保存在命名空间中。然后使用此文件代替 \yii\filters\auth\HttpBearerAuth.
<?php
namespace api\filters\auth;
use api\components\HttpResponseCode;
use yii\db\Exception;
use yii\web\UnauthorizedHttpException;
class HttpBearerAuth extends \yii\filters\auth\HttpBearerAuth {
/**
* @var string the HTTP authentication realm
*/
public $realm = 'api';
public $pattern = FALSE;
public function authenticate($user, $request, $response) {
$authHeader = $request->getHeaders()->get('Authorization');
// Following condition is added to support fastcgi issue.
if ($authHeader === null) {
$authHeader = $this->getBearerAuthFromSession();
$this->pattern = '/^Bearer\s+(.*?)$/';
}
if ($authHeader !== null) {
if ($this->pattern) {
preg_match($this->pattern, $authHeader, $matches);
$identity = $user->loginByAccessToken($matches[1], get_class($this));
} else {
$identity = $user->loginByAccessToken($authHeader, get_class($this));
}
if ($identity === null) {
return $this->handleFailure($response);
}
return $identity;
}
return null;
}
public function challenge($response) {
$response->getHeaders()->set('WWW-Authenticate', "Bearer realm=\"{$this->realm}\"");
}
public function handleFailure($response) {
$e = new UnauthorizedHttpException('Your request was made with invalid credentials.');
throw $e;
}
/**
* In HttpBearerAuth, some development environments do not populate Authorization header in the request;
* The issue is caused by CGI/FastCGI mode in Apache.
* Following lines must be added in api/web/.htaccess:
* # Authorization Headers
* RewriteCond %{HTTP:Authorization} .
* RewriteRule .* - [E=HTTP_AUTHORIZATION:%{HTTP:Authorization}]
*
* This function is used to access the following value in HttpBearerAuth to make it working :
* $_SERVER[‘REDIRECT_HTTP_AUTHORIZATION’].
* @return string|null
*/
public function getBearerAuthFromSession(): ?string {
if (isset($_SERVER['REDIRECT_HTTP_AUTHORIZATION']) && $_SERVER['REDIRECT_HTTP_AUTHORIZATION'] != "") {
return $_SERVER['REDIRECT_HTTP_AUTHORIZATION'];
}
return NULL;
}
}