Yii 2 RESTful API使用OAuth2进行身份验证(Yii 2高级模板)

时间:2015-04-26 17:02:15

标签: api rest oauth-2.0 yii2 yii2-advanced-app

REST API无需身份验证方法即可运行。现在,我想通过移动应用程序对API请求的OAuth2身份验证验证REST API。我试过yii2指南,但它对我不起作用。

基本上移动用户需要使用用户名&密码,如果用户名和密码正确,则用户需要登录,并且需要使用令牌验证进一步的API请求。

我是否需要像这样创建自定义OAuth 2客户端? {{3}}

用户表中的

access_token字段为空。我需要手动保存吗? 如何将access_token作为响应返回?

用户是否有任何理由同时使用这三种方法(HttpBasicAuth,HttpBearerAuth,QueryParamAuth),为什么?怎么样?

我的应用程序文件夹结构如下所示。

/* 1 */
{
    "_id" : ObjectId("553d143ac96712b936005274"),
    "forname" : "Joe",
    "surname" : "Bloggs",
    "DOB" : 12061989,
    "watch" : [ 
        {
            "media_id" : 5000,
            "minutes_watched" : 35
        }, 
        {
            "media_id" : 4567,
            "minutes_watched" : 20
        }, 
        {
            "media_id" : 1234,
            "minutes_watched" : 58
        }
    ]
}

API \模块\ V1 \ Module.php

api
-config
-modules
--v1
---controllers
---models
-runtime
-tests
-web

backend
common
console
environments
frontend

API \模块\ V1 \控制器\ CountryController.php

namespace api\modules\v1;
class Module extends \yii\base\Module
{
    public $controllerNamespace = 'api\modules\v1\controllers';

    public function init()
    {
        parent::init(); 
        \Yii::$app->user->enableSession = false;       
    }   
}

常见\模型\ user.php的

namespace api\modules\v1\controllers;
use Yii;
use yii\rest\ActiveController;
use common\models\LoginForm;
use common\models\User;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;

/**
 * Country Controller API
 *
 * @author Budi Irawan <deerawan@gmail.com>
 */
class CountryController extends ActiveController
{
    public $modelClass = 'api\modules\v1\models\Country';    

    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['authenticator'] = [
            //'class' => HttpBasicAuth::className(),
            'class' => CompositeAuth::className(),
            'authMethods' => [
                HttpBasicAuth::className(),
                HttpBearerAuth::className(),
                QueryParamAuth::className(),
            ],
        ];
        return $behaviors;
    }

}

用户表

namespace common\models;

use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;

class User extends ActiveRecord implements IdentityInterface
{
    const STATUS_DELETED = 0;
    const STATUS_ACTIVE = 10;

    public static function tableName()
    {
        return '{{%user}}';
    }

    public function behaviors()
    {
        return [
            TimestampBehavior::className(),
        ];
    }

    public function rules()
    {
        return [
            ['status', 'default', 'value' => self::STATUS_ACTIVE],
            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
        ];
    }

    public static function findIdentity($id)
    {
        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
    }

    public static function findIdentityByAccessToken($token, $type = null)
    {

        return static::findOne(['access_token' => $token]);
    }


}
迁移用户表

后添加了

access_token

3 个答案:

答案 0 :(得分:5)

我正在使用JWT来验证请求。基本上,JWT是一个令牌,它还包含有关用户的信息,以及令牌本身的信息,例如令牌的有效性和到期时间。您可以阅读有关JWT here的更多信息。

我的申请流程如下:

  • 首先,当用户登录时,为用户创建JWT

    $key = base64_decode('some_random_string');
    
    $tokenId = base64_encode(mcrypt_create_iv(32));
    $issuedAt = time();
    $notBefore = $issuedAt + 5;
    $expire = $notBefore + 1800;
    
    $user = User::findByEmail($email);
    
    $data = [
        'iss' => 'your-site.com',
        'iat' => $issuedAt,
        'jti' => $tokenId,
        'nbf' => $notBefore,
        'exp' => $expire,
        'data' => [
            'id' => $user->id,
            'username' => $user->username,
            //put everything you want (that not sensitive) in here
        ]
    ];
    
    $jwt = JWT::encode($data, $key,'HS256');
    
    return $jwt;
    
  • 然后,客户端(例如移动应用程序)必须通过Authorization标头在每个请求中提供令牌。标题将如下所示:

    Authorization:Bearer [the JWT token without bracket]

  • 在User模型中,添加这样的方法来验证令牌:

    public static function findIdentityByAccessToken($token, $type = null) {
        $key = base64_decode('the same key that used in login function');
    
        try{
            $decoded = JWT::decode($token, $key, array('HS256'));
            return static::findByEmail($decoded->data->email);
        }catch (\Exception $e){
            return null;
        }
    }
    

    如果令牌不再无效(已被篡改或已超过到期时间),JWT库将引发异常。

  • 然后,将其添加到每个控制器中的behavior函数中:

    $behaviors['authenticator'] = [
        'class' => HttpBearerAuth::className(),
        'except' => ['login'] //action that you don't want to authenticate such as login
    ];
    

就是这样!我希望这项工作与你想要的一样。哦,你可以使用很多JWT库(你可以看到here),但我个人使用this library by people from firebase

答案 1 :(得分:1)

您可以创建您的Auth系统,通常我会这样做。 您可以为每个用户保存令牌,然后通过该令牌对用户进行身份验证。 在每个操作中,您都可以为authentify用户发送该令牌。

答案 2 :(得分:1)

您需要执行以下操作:

  • 在将用户保存在用户模型中之前设置令牌。
  • 在UserController中添加actionLogin以返回用户登录时的auth_key。
  • 在每个API请求中,您在标头中发送auth_key而不是 发送用户名和密码。
  • 检查auth_key是否有效,定义&#39; authenticator&#39;在里面 UserController行为。

您可以在我对另一个问题here

的回答中找到代码示例