0
votes

Here is my Controller

class ClientController extends ActiveController
{
    public $modelClass = 'common\models\Client'; 
    public $serializer = [
      'class' => 'yii\rest\Serializer',
      'collectionEnvelope' => 'items',
  ];
    public function behaviors()
    {

        return ArrayHelper::meenter code hererge(parent::behaviors(),[
          [
            'class' => \yii\filters\Cors::className(),
        ],
           [
           'class' => CompositeAuth::className(),
           'except' => ['options'],
           'authMethods' => [
           HttpBearerAuth::className(),
             QueryParamAuth::className(),

           ],
        ],

           [
           'class' => TimestampBehavior::className(),
           ],
             [
              'class' => 'yii\filters\ContentNegotiator',
              'only' => ['view', 'index'],  // in a controller
              // if in a module, use the following IDs for user actions
              // 'only' => ['user/view', 'user/index']
              'formats' => [
                  'application/json' => Response::FORMAT_JSON,
              ],

          ],
           [
           'class' => AccessControl::className(),
    // We will override the default rule config with the new AccessRule class
           'ruleConfig' => [
           'class' => AccessRule::className(),
           ],
           'only' => ['create', 'delete'],
           'rules' => [[
           'actions' => ['create'],
           'allow' => true,
            // Allow users, moderators and admins to create
           'roles' => [
           User::ROLE_ADMIN
           ],
        ],

           [
           'actions' => ['delete'],
           'allow' => true,
            // Allow admins to delete
           'roles' => [
           User::ROLE_ADMIN
           ],
        ],
      ],
    ],
  ]);

  }
   public function actions(){
       $actions = parent::actions();
      unset( $actions['create']);
      return $actions;
   }
   public function actionCreate(){

       $model = new \common\models\Client();
       $transaction = Yii::$app->db->beginTransaction();
       try 
       {

        $model->load(Yii::$app->getRequest()->getBodyParams(), '');
        $user_create = \common\models\User::user_create($model);
        if($user_create){
           $model->user_id = $user_create->id;
          if($model->save()){
            $transaction->commit();
            return $model;
          }
        }

       }
        catch (Exception $e) 
        {
          $transaction->rollBack();
          return null;
        }    
   }
Here is my User Model
class User extends ActiveRecord implements IdentityInterface
{

    public static function findIdentity($id)
    {
        return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]);
    }
    public function generateAccountActivationToken()
    {
        $this->account_activation_token = Yii::$app->security->generateRandomString() . '_' . time();
    }
    /**
     * @inheritdoc
     */
    // public static function findIdentityByAccessToken($token, $type = null)
    // {
    //     throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.');
    // }
    public static function findIdentityByAccessToken($token, $type = null)
    {
        return static::findOne(['auth_key' => $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)
    {
        $expire = Yii::$app->params['user.passwordResetTokenExpire'];
        $parts = explode('_', $token);
        $timestamp = (int) end($parts);
        if ($timestamp + $expire < time()) {
            // token expired
            return null;
        }

    /**
     * @inheritdoc
     */
    public function getId()
    {
        return $this->getPrimaryKey();
    }

    /**
     * @inheritdoc
     */
    public function getAuthKey()
    {
        return $this->auth_key;
        // return null;

    }

    /**
     * @inheritdoc
     */
    public function validateAuthKey($authKey)
    {
        return $this->getAuthKey() === $authKey;
    }

    /**
     * Generates "remember me" authentication key
     */
    public function generateAuthKey()
    {
        $this->auth_key = Yii::$app->security->generateRandomKey();

    }


    public function beforeSave($insert)
    {
        if (parent::beforeSave($insert)) {
            if ($this->isNewRecord) {
                $this->auth_key = \Yii::$app->security->generateRandomString();
            }
            return true;
        }
        return false;
    }
}

The issue here is when i send post request it return 401 error.I know it is athentication error it even didnt hit the function public static function findIdentityByAccessToken($token, $type = null) { return static::findOne(['auth_key' => $token]); } I kown the issue is here at HttpBearerAuth::className(). How i can fix this error here is the image enter image description here

1
@Muhammad Omer Aslam Have a look bro what goning wrong here.The login and sinup action in user controller working fine.If i remove the behaviour the the action create in client also working,now the issue is in access-token processing HttpBearerAuth::className().rajwa766
added an answer for youMuhammad Omer Aslam

1 Answers

1
votes

About the statement

It does not even land on the findIdentityByAccessToken()

From the DOCS

After authentication, for every API request, the requested controller will try to authenticate the user in its beforeAction() step.

If authentication succeeds, the controller will perform other checks (such as rate limiting, authorization) and then run the action. The authenticated user identity information can be retrieved via Yii::$app->user->identity.

If authentication fails, a response with HTTP status 401 will be sent back together with other appropriate headers (such as a WWW-Authenticate header for HTTP Basic Auth).

HttpBearerAuth extends HttpHeaderAuth which is an action filter that supports HTTP authentication through HTTP Headers, look into the source code for the HttpHeaderAuth function authenticate($user, $request, $response) you will see it gets the auth headers in the very first line

$authHeader = $request->getHeaders()->get($this->header);

and returns $identity only if the authHeaders are not null, otherwise it returns null from the authenticate($user, $request, $response) method and you receive a 401 error without even landing on the findIdentityByAccesToken().

What you should do is

  • Open postman and click on the Authorization tab

enter image description here

  • Select the Type from the drop-down BearerToken

enter image description here

  • on the right side add the auth_key from the user table for the user that you are sending the request against

enter image description here

  • Click on the Preview Request Button and you will see the message request headers were updated

enter image description here

now if you go to the Headers tab that is very next to the Authorization tab you will see the key=>value pair of the authorization headers

enter image description here

Now click on send Button and see your request go I will recommend you to comment out everything from the action currently, and just add a echo "hello"; statement to know that it landed there.


You can send the headers via curl for authentication in the following way

curl -d "param1=value1&param2=value2" 
-H "Content-Type: application/x-www-form-urlencoded" 
-H "Authorization: Bearer YOUR_TOKEN_" 
-X POST http://localhost:3000/data