【问题标题】:Yii2 and OAuth2 Plugin Filsh/yii2-oauth2-server: Unauthorized when sending POST dataYii2 和 OAuth2 插件 Filsh/yii2-oauth2-server:发送 POST 数据时未授权
【发布时间】:2016-06-21 14:15:58
【问题描述】:

编辑:已解决

显然这个插件有一些问题缺少请求标头。解决方案是添加

SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0

到 .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);
            },
        });
    }

返回

未经授权:您使用无效凭据请求

当我改为 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";
}

}

这是我的配置对象

'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
            ]
        ]
    ]

这是 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 与 oauth 用户位于不同的表中,这就是我首先查询它的原因) .

有什么想法吗?

【问题讨论】:

  • 请发布错误
  • 它已经发布了。但这是完整的 json: {"name":"Unauthorized","message":"You are request with an invalid credential.","code":0,"status":401,"type":"yii\ \web\\UnauthorizedHttpException"}
  • 我正在寻找代码(401),好的,谢谢
  • 一般这种错误应该是没有在表单(POST)中发送csrf参数
  • 我想,它是作为 cookie 发送的:Cookie:_csrf=7fb13214043dae81f560d6b577f15655f8955c61caf42224bf1d5b57eb3a7a55a%3A2%3A%7Bi%3A0%3Bs%3A5%3A%22_csrf%22%3Bi%3A1%3Bs%3A32%3A%2281928Pj8BIQYHiDD504Y0cb-yYuR_V3Q%22%3B%7D; PHPSESSID=m39veuj4oreogbsri9p6sr9367

标签: php yii2 oauth2


【解决方案1】:

我不知道您正在使用的插件,但我知道您可以在实现 OAuth 2.0 时使用 Yii2 HttpBearerAuth 过滤器,这意味着使用 HTTP Bearer token。并且该令牌通常与 HTTP 请求的 Authorization 标头而不是正文请求一起传递,它通常看起来像:

Authorization: Bearer y-9hFW-NhrI1PK7VAXYdYukwWVrNTkQ1

这个想法是将您从服务器收到的token保存在某个地方(应该是一个安全的地方)并将其包含在需要服务器授权的请求的标头中(也许更好地解释hereherehere) 所以你用来发送 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);
        },
    });
}

同时检查 User 类(在您的配置文件中定义并负责对用户进行身份验证的类)检查 findIdentityByAccessToken() 方法的实现。它通常应该是这样的(更多细节请参见Yii docs):

public static function findIdentityByAccessToken($token, $type = null)
{
    return static::findOne(['auth_key' => $token]);
}

这是接收token的函数,当身份验证失败时它应该返回null默认情况下findOne()在没有找到记录时返回null)或返回一个用户实例来注册它并使其在应用程序内的任何位置的Yii::$app-&gt;user-&gt;identityYii::$app-&gt;user-&gt;id 中可访问,这样您就可以在其中实现所需的任何逻辑,例如检查访问令牌的有效性或其是否存在于不同的表中。

【讨论】:

  • 感谢塞勒姆,这为我指明了新的方向。无论如何,我已经更新了我的答案,请检查,我仍然有 401 作为响应。
  • 尝试在findIdentityByAccessToken() 中添加exit('token : ' . $token); 或等效代码作为第一行代码,以首先查看令牌是否到达那里。使用任何浏览器开发工具的网络选项卡来查看您在发送该 POST 请求时得到的响应。如果 HttpBearerAuth 过滤器工作正常,您应该会看到 token : XXX 其中 XXX 是您发送的令牌。如果不是,请尝试仅使用 HttpBearerAuth 进行测试建议,例如 here
  • 还有一件事。一件重要的事情。如果您的浏览器在 POST 请求之前发送 OPTIONS 请求,请检查网络开发工具。它可能是被拒绝的那个。或尝试使用邮递员之类的工具,看看您的服务器是否同时拒绝 POST 和 OPTIONS 或仅拒绝 OPTIONS
【解决方案2】:

显然这个插件(Filsh/yii2-oauth2-server)在缺少请求标头时遇到了一些问题。解决方案是添加

SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0

到 .htaccess 文件以使 Authorizaion 变量可用,如下所示:

https://github.com/yiisoft/yii2/issues/6631

【讨论】:

    猜你喜欢
    • 2015-04-02
    • 1970-01-01
    • 2017-04-27
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2021-09-21
    • 1970-01-01
    • 2020-07-07
    相关资源
    最近更新 更多