Yii2 和 OAuth2 插件 Filsh/yii2-oauth2-server:发送 POST 数据时未经授权
Yii2 and OAuth2 Plugin Filsh/yii2-oauth2-server: Unauthorized when sending POST data
编辑:已解决
显然这个插件有一些问题缺少请求headers。解决方案是添加
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=[=12=]
到 .htaccess 文件以使 Authorizaion 变量可用,如此问题报告所述:
https://github.com/yiisoft/yii2/issues/6631
我目前正在使用 Yii2 并使用 this OAuth2 plugin (Filsh/yii2-oauth2-server) 登录并使用移动 HTML5 应用程序中的令牌。
我已经配置了一切,它正在检索令牌,但是当我尝试通过 POST 发送令牌时,它会抛出一个错误。
我首先调用 send()
来检索令牌。
function send(){
var url = "http://www.server.org/app/api/oauth2/rest/token";
var data = {
'grant_type':'password',
'username':'user',
'password':'pass',
'client_id':'clientid',
'client_secret':'clientsecret',
};
$.ajax({
type: "POST",
url: url,
data: data,
success:function(data){
console.log(data);
token = data.access_token;
},
})
};
然后当我执行此操作时调用 createuser()
。
function createuser(){
var url = "http://www.server.org/app/api/v1/users/create";
var data = {
'callback':'asdf',
'username': 'user',
'password':'pass',
'first_name':'name',
'last_name':'lastname'
};
$.ajax({
type: "POST",
url: url,
data: data,
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
},
success:function(r){
console.log(r);
},
});
}
它returns
Unauthorized: You are requesting with an invalid credential
当我改为 GET 时,它工作正常。
这是我的控制器,我已经在使用:
['class' => HttpBearerAuth::className()],
['class' => QueryParamAuth::className(), 'tokenParam' => 'accessToken'],
作为身份验证方法。
<?php
namespace app\api\modules\v1\controllers;
use Yii;
use app\models\OauthUsers;
use yii\rest\ActiveController;
use yii\web\Response;
use yii\helpers\ArrayHelper;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;
use filsh\yii2\oauth2server\filters\ErrorToExceptionFilter;
use filsh\yii2\oauth2server\filters\auth\CompositeAuth;
class UsersController extends \yii\web\Controller
{
public function behaviors()
{
return ArrayHelper::merge(parent::behaviors(), [
'authenticator' => [
'class' => CompositeAuth::className(),
'authMethods' => [
['class' => HttpBearerAuth::className()],
['class' => QueryParamAuth::className(), 'tokenParam' => 'accessToken'],
]
],
'exceptionFilter' => [
'class' => ErrorToExceptionFilter::className()
],
'class' => \yii\filters\ContentNegotiator::className(),
]);
}
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionCreate()
{
$model = new OauthUsers;
try {
if ($model->load($_POST) && $model->save()) {
return $this->redirect(Url::previous());
} elseif (!\Yii::$app->request->isPost) {
$model->load($_GET);
}
} catch (\Exception $e) {
$msg = (isset($e->errorInfo[2]))?$e->errorInfo[2]:$e->getMessage();
$model->addError('_exception', $msg);
}
return "true";
}
}
这是我的配置object
'oauth2' => [
'class' => 'filsh\yii2\oauth2server\Module',
'tokenParamName' => 'accessToken',
'tokenAccessLifetime' => 3600 * 24,
'storageMap' => [
'user_credentials' => 'app\models\OauthUsers',
],
'grantTypes' => [
'user_credentials' => [
'class' => 'OAuth2\GrantType\UserCredentials',
],
'refresh_token' => [
'class' => 'OAuth2\GrantType\RefreshToken',
'always_issue_new_refresh_token' => true
]
]
]
这是 class OauthUsers
<?php
namespace app\models;
use Yii;
use \app\models\base\OauthUsers as BaseOauthUsers;
/**
* This is the model class for table "oauth_users".
*/
class OauthUsers extends BaseOauthUsers
implements \yii\web\IdentityInterface,\OAuth2\Storage\UserCredentialsInterface
{
/**
* @inheritdoc
*/
public static function findIdentity($id) {
$dbUser = OauthUsers::find()
->where([
"id" => $id
])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
/**
* @inheritdoc
*/
public static function findIdentityByAccessToken($token, $userType = null) {
$at = OauthAccessTokens::find()
->where(["access_token" => $token])
->one();
$dbUser = OauthUsers::find()
->where(["id" => $at->user_id])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
/**
* Implemented for Oauth2 Interface
*/
public function checkUserCredentials($username, $password)
{
$user = static::findByUsername($username);
if (empty($user)) {
return false;
}
return $user->validatePassword($password);
}
/**
* Implemented for Oauth2 Interface
*/
public function getUserDetails($username)
{
$user = static::findByUsername($username);
return ['user_id' => $user->getId()];
}
/**
* Finds user by username
*
* @param string $username
* @return static|null
*/
public static function findByUsername($username) {
$dbUser = OauthUsers::find()
->where([
"username" => $username
])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
/**
* @inheritdoc
*/
public function getId()
{
return $this->id;
}
/**
* @inheritdoc
*/
public function getAuthKey()
{
return $this->authKey;
}
/**
* @inheritdoc
*/
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
/**
* Validates password
*
* @param string $password password to validate
* @return boolean if password provided is valid for current user
*/
public function validatePassword($password)
{
return $this->password === $password;
}
}
我也更改了 createuser
,但仍然收到 401。我不确定它是否通过 findIdentityByAccessToken
(access_token 在另一个 table 而不是 oauth 用户,这就是我首先查询它的原因)。
有什么想法吗?
我不知道你用的是什么插件,但我知道你可以使用 Yii2 HttpBearerAuth filter when implementing OAuth 2.0 which means using the HTTP Bearer token。该令牌通常与 HTTP 请求的授权 header 而不是 body 请求一起传递,它通常看起来像:
Authorization: Bearer y-9hFW-NhrI1PK7VAXYdYukwWVrNTkQ1
这个想法是将您从服务器收到的 token
保存在某个地方(应该是一个安全的地方)并将其包含在需要服务器授权的请求的 header 中(可能更好解释 here, here or here) 所以你用来发送 POST 请求的 JS 代码应该看起来更像这样:
function createuser(){
var url = "http://www.server.org/app/api/v1/users/create";
var data = {
'callback':'cb',
'username': 'user',
'password':'pass',
'first_name':'name',
'last_name':'lastname'
};
$.ajax({
type: "POST",
url: url,
data: data,
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
},
success:function(r){
console.log(r);
},
});
}
同时检查用户 class(在您的配置文件中定义并负责对用户进行身份验证的用户)检查 findIdentityByAccessToken() method. it should usually look like this (see Yii docs 的实现以获取更多详细信息) :
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['auth_key' => $token]);
}
这是将接收 token
的函数,当身份验证失败时它应该 return null
( 默认 findOne() returns null when no record is found) or returns a User instance to register it and make it accessible within Yii::$app->user->identity
or Yii::$app->user->id
anywhere in your app so you可以在其中实现您需要的任何逻辑,例如检查访问令牌的有效性或其在不同 table.
中的存在
显然这个插件 (Filsh/yii2-oauth2-server) 在缺少请求 headers 时遇到了一些问题。解决方案是添加
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=[=10=]
到 .htaccess 文件以使 Authorizaion 变量可用,如下所示:
https://github.com/yiisoft/yii2/issues/6631
编辑:已解决
显然这个插件有一些问题缺少请求headers。解决方案是添加
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=[=12=]
到 .htaccess 文件以使 Authorizaion 变量可用,如此问题报告所述:
https://github.com/yiisoft/yii2/issues/6631
我目前正在使用 Yii2 并使用 this OAuth2 plugin (Filsh/yii2-oauth2-server) 登录并使用移动 HTML5 应用程序中的令牌。
我已经配置了一切,它正在检索令牌,但是当我尝试通过 POST 发送令牌时,它会抛出一个错误。
我首先调用 send()
来检索令牌。
function send(){
var url = "http://www.server.org/app/api/oauth2/rest/token";
var data = {
'grant_type':'password',
'username':'user',
'password':'pass',
'client_id':'clientid',
'client_secret':'clientsecret',
};
$.ajax({
type: "POST",
url: url,
data: data,
success:function(data){
console.log(data);
token = data.access_token;
},
})
};
然后当我执行此操作时调用 createuser()
。
function createuser(){
var url = "http://www.server.org/app/api/v1/users/create";
var data = {
'callback':'asdf',
'username': 'user',
'password':'pass',
'first_name':'name',
'last_name':'lastname'
};
$.ajax({
type: "POST",
url: url,
data: data,
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
},
success:function(r){
console.log(r);
},
});
}
它returns
Unauthorized: You are requesting with an invalid credential
当我改为 GET 时,它工作正常。
这是我的控制器,我已经在使用:
['class' => HttpBearerAuth::className()], ['class' => QueryParamAuth::className(), 'tokenParam' => 'accessToken'],
作为身份验证方法。
<?php
namespace app\api\modules\v1\controllers;
use Yii;
use app\models\OauthUsers;
use yii\rest\ActiveController;
use yii\web\Response;
use yii\helpers\ArrayHelper;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;
use filsh\yii2\oauth2server\filters\ErrorToExceptionFilter;
use filsh\yii2\oauth2server\filters\auth\CompositeAuth;
class UsersController extends \yii\web\Controller
{
public function behaviors()
{
return ArrayHelper::merge(parent::behaviors(), [
'authenticator' => [
'class' => CompositeAuth::className(),
'authMethods' => [
['class' => HttpBearerAuth::className()],
['class' => QueryParamAuth::className(), 'tokenParam' => 'accessToken'],
]
],
'exceptionFilter' => [
'class' => ErrorToExceptionFilter::className()
],
'class' => \yii\filters\ContentNegotiator::className(),
]);
}
/**
* Creates a new model.
* If creation is successful, the browser will be redirected to the 'view' page.
* @return mixed
*/
public function actionCreate()
{
$model = new OauthUsers;
try {
if ($model->load($_POST) && $model->save()) {
return $this->redirect(Url::previous());
} elseif (!\Yii::$app->request->isPost) {
$model->load($_GET);
}
} catch (\Exception $e) {
$msg = (isset($e->errorInfo[2]))?$e->errorInfo[2]:$e->getMessage();
$model->addError('_exception', $msg);
}
return "true";
}
}
这是我的配置object
'oauth2' => [
'class' => 'filsh\yii2\oauth2server\Module',
'tokenParamName' => 'accessToken',
'tokenAccessLifetime' => 3600 * 24,
'storageMap' => [
'user_credentials' => 'app\models\OauthUsers',
],
'grantTypes' => [
'user_credentials' => [
'class' => 'OAuth2\GrantType\UserCredentials',
],
'refresh_token' => [
'class' => 'OAuth2\GrantType\RefreshToken',
'always_issue_new_refresh_token' => true
]
]
]
这是 class OauthUsers
<?php
namespace app\models;
use Yii;
use \app\models\base\OauthUsers as BaseOauthUsers;
/**
* This is the model class for table "oauth_users".
*/
class OauthUsers extends BaseOauthUsers
implements \yii\web\IdentityInterface,\OAuth2\Storage\UserCredentialsInterface
{
/**
* @inheritdoc
*/
public static function findIdentity($id) {
$dbUser = OauthUsers::find()
->where([
"id" => $id
])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
/**
* @inheritdoc
*/
public static function findIdentityByAccessToken($token, $userType = null) {
$at = OauthAccessTokens::find()
->where(["access_token" => $token])
->one();
$dbUser = OauthUsers::find()
->where(["id" => $at->user_id])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
/**
* Implemented for Oauth2 Interface
*/
public function checkUserCredentials($username, $password)
{
$user = static::findByUsername($username);
if (empty($user)) {
return false;
}
return $user->validatePassword($password);
}
/**
* Implemented for Oauth2 Interface
*/
public function getUserDetails($username)
{
$user = static::findByUsername($username);
return ['user_id' => $user->getId()];
}
/**
* Finds user by username
*
* @param string $username
* @return static|null
*/
public static function findByUsername($username) {
$dbUser = OauthUsers::find()
->where([
"username" => $username
])
->one();
if (!count($dbUser)) {
return null;
}
return new static($dbUser);
}
/**
* @inheritdoc
*/
public function getId()
{
return $this->id;
}
/**
* @inheritdoc
*/
public function getAuthKey()
{
return $this->authKey;
}
/**
* @inheritdoc
*/
public function validateAuthKey($authKey)
{
return $this->authKey === $authKey;
}
/**
* Validates password
*
* @param string $password password to validate
* @return boolean if password provided is valid for current user
*/
public function validatePassword($password)
{
return $this->password === $password;
}
}
我也更改了 createuser
,但仍然收到 401。我不确定它是否通过 findIdentityByAccessToken
(access_token 在另一个 table 而不是 oauth 用户,这就是我首先查询它的原因)。
有什么想法吗?
我不知道你用的是什么插件,但我知道你可以使用 Yii2 HttpBearerAuth filter when implementing OAuth 2.0 which means using the HTTP Bearer token。该令牌通常与 HTTP 请求的授权 header 而不是 body 请求一起传递,它通常看起来像:
Authorization: Bearer y-9hFW-NhrI1PK7VAXYdYukwWVrNTkQ1
这个想法是将您从服务器收到的 token
保存在某个地方(应该是一个安全的地方)并将其包含在需要服务器授权的请求的 header 中(可能更好解释 here, here or here) 所以你用来发送 POST 请求的 JS 代码应该看起来更像这样:
function createuser(){
var url = "http://www.server.org/app/api/v1/users/create";
var data = {
'callback':'cb',
'username': 'user',
'password':'pass',
'first_name':'name',
'last_name':'lastname'
};
$.ajax({
type: "POST",
url: url,
data: data,
beforeSend: function (xhr) {
xhr.setRequestHeader('Authorization', 'Bearer ' + token);
},
success:function(r){
console.log(r);
},
});
}
同时检查用户 class(在您的配置文件中定义并负责对用户进行身份验证的用户)检查 findIdentityByAccessToken() method. it should usually look like this (see Yii docs 的实现以获取更多详细信息) :
public static function findIdentityByAccessToken($token, $type = null)
{
return static::findOne(['auth_key' => $token]);
}
这是将接收 token
的函数,当身份验证失败时它应该 return null
( 默认 findOne() returns null when no record is found) or returns a User instance to register it and make it accessible within Yii::$app->user->identity
or Yii::$app->user->id
anywhere in your app so you可以在其中实现您需要的任何逻辑,例如检查访问令牌的有效性或其在不同 table.
显然这个插件 (Filsh/yii2-oauth2-server) 在缺少请求 headers 时遇到了一些问题。解决方案是添加
SetEnvIf Authorization .+ HTTP_AUTHORIZATION=[=10=]
到 .htaccess 文件以使 Authorizaion 变量可用,如下所示:
https://github.com/yiisoft/yii2/issues/6631