Yii2 REST api bearer authentication

12,868

Solution 1

I had the same case you did. I am using ReactJS for client dan Yii2 for api.

In your case, check this rule:

[
    'class' => 'yii\rest\UrlRule',
    'controller' => 'v1/checkins', 
    'extraPatterns' => [
     'GET checkinview/<id:\d+>' => 'checkinview/'
    ],     
]

This code should be:

[
    'class' => 'yii\rest\UrlRule',
    'controller' => 'v1/checkins', 
    'tokens' => ['{id}' => '<id:\\w+>'], --> because you stil use ActiveController
    'pluralize' => false, --> for disable pluralize
    'extraPatterns' => [
     'GET checkinview/<id:\d+>' => 'checkinview' --> remove '/' sign
     'OPTIONS checkinview/<id:\d+>' => 'options', --> for corsFilter
    ],     
]

Solution 2

  • Give me "user.php" for checking more...
  • The "CheckinsController" should like below LOCs (don't add more information when you don't control it).

    namespace api\modules\v1\controllers;

    use yii\rest\ActiveController;
    use yii\data\ActiveDataProvider;
    use yii\filters\ContentNegotiator;
    use api\modules\v1\models\CheckinApi;
    use yii\filters\auth\HttpBearerAuth;
    use yii\web\Response;

    class CheckinsController extends ActiveController
    {
        public $modelClass = 'common\models\Events';

    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['authenticator'] = [
            'class' => HttpBearerAuth::className()   
        ]; 
        return $behaviors;
    } 
    }
Share:
12,868
Admin
Author by

Admin

Updated on July 15, 2022

Comments

  • Admin
    Admin almost 2 years

    I am using Yii2 framework as the backend and react js for the client side. I am trying to create REST api with HTTPBearer authentication but always get a 401 Unauthorized error. I have followed the Yii2 Rest api authentication with no success. I have also implemented findIdentityByAccessToken on user.php and access_token on my sql. My files:-

    Folder structure:-

    -api
        --config
          --main.php
          --main-local.php
          ...
        --modules
          --v1
           --controllers
             --CheckinsController.php

    -backend
    -common
    -frontend ..

    main.php

     <?php
    
    $params = array_merge(
        require(__DIR__ . '/../../common/config/params.php'),
        require(__DIR__ . '/../../common/config/params-local.php'),
        require(__DIR__ . '/params.php'),
        require(__DIR__ . '/params-local.php')
    );
    
    return [
        'id' => 'app-api',
        'basePath' => dirname(__DIR__),
        'bootstrap' => ['log'],
        'modules' => [
            'v1' => [
                'basePath' => '@app/modules/v1',
                'class' => 'api\modules\v1\Module'   // here is our v1 modules
            ]
        ],
        'components' => [
            'user' => [
                'identityClass' => 'common\models\User',
                'enableAutoLogin' => false,
                'enableSession' => false,
                'loginUrl' =>'',
            ],
            'log' => [
                'traceLevel' => YII_DEBUG ? 3 : 0,
                'targets' => [
                    [
                        'class' => 'yii\log\FileTarget',
                        'levels' => ['error', 'warning'],
                    ],
                ],
            ],
            'request' => [
                'class' => '\yii\web\Request',
                'enableCookieValidation' => false,
        'parsers' => [
            'application/json' => 'yii\web\JsonParser',
        ]
    ],
            'urlManager' => [
                'enablePrettyUrl' => true,
                'enableStrictParsing' => true,
                'showScriptName' => false,
                'rules' => [
                    [
                        'class' => 'yii\rest\UrlRule',
                        'controller' => 'v1/user', 
                        'tokens' => [
                            '{id}' => '<id:\\w+>'
                        ]
                    ],
                      [
                        'class' => 'yii\rest\UrlRule',
                        'controller' => 'v1/event', 
                        'extraPatterns' => [
                        'GET test' => 'test'
                        ],     
                    ],
                    [
                        'class' => 'yii\rest\UrlRule',
                        'controller' => 'v1/checkins', 
                        'extraPatterns' => [
                         'GET checkinview/<id:\d+>' => 'checkinview/'
                        ],     
                    ]
                ],
            ]
        ],
        'params' => $params,
    ];
    

    CheckinsController.php

    namespace api\modules\v1\controllers;
    
    use yii\rest\ActiveController;
    use yii\data\ActiveDataProvider;
    use yii\filters\ContentNegotiator;
    use api\modules\v1\models\CheckinApi;
    use yii\filters\auth\HttpBearerAuth;
    use yii\web\Response;
    
    class CheckinsController extends ActiveController
    {
        public $modelClass = 'common\models\Events';
    
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['authenticator'] = [
            'class' => HttpBearerAuth::className()   
        ];
         $behaviors['contentNegotiator'] = [
                'class' => ContentNegotiator::className(),
                'formats' => [
                    'application/json' => Response::FORMAT_JSON,
                ],
            ];
    
        return $behaviors;
    }
    
    
    public function actionCheckinview($id)
    {
    //     \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;
        $query = new CheckinApi();
        $test = 
            [
                'count' => $query->Checkincount($id),
                'checkinid' => $id,
                'useridused' => Yii::$app->user->identity->id,
    
            ];
             return $test;//Testing purpose
    }
    }
    
    User.php
    
    class User extends ActiveRecord implements IdentityInterface
    {
    const STATUS_DELETED = 0;
    const STATUS_ACTIVE = 10;
    
    /**
     * @inheritdoc
     */
    public static function tableName()
    {
        return '{{%user}}';
    }
    
    /**
     * @inheritdoc
     */
    public function behaviors()
    {
        return [
            TimestampBehavior::className(),
        ];
    }
    
    /**
     * @inheritdoc
     */
    public function rules()
    {
        return [
            ['status', 'default', 'value' => self::STATUS_ACTIVE],
            ['status', 'in', 'range' => [self::STATUS_ACTIVE, self::STATUS_DELETED]],
        ];
    }
    
    public function fields()
    {
        $fields = parent::fields();
    
        // remove fields that contain sensitive information
        unset($fields['auth_key'], $fields['password_hash'], $fields['password_reset_token'],$fields['access_token']);
    
        return $fields;
    }
    
    /**
     * @inheritdoc
     */
    public static function findIdentity($id)
    {
        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
    }
    
    /**
     * @inheritdoc
     */
    public static function findIdentityByAccessToken($token, $type = null)
    {
         return static::findOne(['access_token' => $token]);
    }
    
    /**
     * Finds user by username
     *
     * @param string $username
     * @return static|null
     */
    public static function findByUsername($username)
    {
        return static::findOne(['username' => $username, 'status' => self::STATUS_ACTIVE]);
    }
    
    /**
     * Finds user by password reset token
     *
     * @param string $token password reset token
     * @return static|null
     */
    public static function findByPasswordResetToken($token)
    {
        if (!static::isPasswordResetTokenValid($token)) {
            return null;
        }
    
        return static::findOne([
            'password_reset_token' => $token,
            'status' => self::STATUS_ACTIVE,
        ]);
    }
    
    /**
     * Finds out if password reset token is valid
     *
     * @param string $token password reset token
     * @return boolean
     */
    public static function isPasswordResetTokenValid($token)
    {
        if (empty($token)) {
            return false;
        }
        $expire = Yii::$app->params['user.passwordResetTokenExpire'];
        $parts = explode('_', $token);
        $timestamp = (int) end($parts);
        return $timestamp + $expire >= time();
    }
    
    /**
     * @inheritdoc
     */
    public function getId()
    {
        return $this->getPrimaryKey();
    }
    
    /**
     * @inheritdoc
     */
    public function getAuthKey()
    {
        return $this->auth_key;
    }
    
    /**
     * @inheritdoc
     */
    public function validateAuthKey($authKey)
    {
        return $this->getAuthKey() === $authKey;
    }
    
    /**
     * Validates password
     *
     * @param string $password password to validate
     * @return boolean if password provided is valid for current user
     */
    public function validatePassword($password)
    {
        return Yii::$app->security->validatePassword($password, $this->password_hash);
    }
    
    /**
     * Generates password hash from password and sets it to the model
     *
     * @param string $password
     */
    public function setPassword($password)
    {
        $this->password_hash = Yii::$app->security->generatePasswordHash($password);
    }
    
    /**
     * Generates "remember me" authentication key
     */
    public function generateAuthKey()
    {
        $this->auth_key = Yii::$app->security->generateRandomString();
    }
    
     /**
     * Generates "api" access token
     */
    public function generateAccessToken()
    {
        $this->access_token = Yii::$app->security->generateRandomString($length = 16);
    }
    
    /**
     * Generates new password reset token
     */
    public function generatePasswordResetToken()
    {
        $this->password_reset_token = Yii::$app->security-       >generateRandomString() . '_' . time();
    }
    
    /**
     * Removes password reset token
     */
    public function removePasswordResetToken()
    {
        $this->password_reset_token = null;
    }
    }
    

    Any help would be much appreciated!! trying to get around this problem for days, but no success. Dont know if it is a simple error done by me!!