Yii2 Rest API Auhorization a Very Simple Implementation

Rest API in Yii2 has explained very straighforward and clear, then we could implement it in our web app easily, but for rest api Authorization for some beginner level developers will face heavy difficulties to implement.

After years of search and trial, finally I got very simple how to put Yii2 REST API Authorization that will make our end-point only accessible to dedicated client web page.

There are 5 modifications we have to do:

  1. config\main.php
  2. common\models\User.php
  3. end-point
  4. client controller
  5. client view address

Let’s jump into the detail.

  1. Modification of config\main.php

Assume our end-point is build in Yii2 advance template.

Go to frontend\config, then open main.php. Point to ‘components’, add two line in ‘user’

'user'=>[ ..., ... 'enableSession' => false, 'loginUrl' => null, ... ],

Save your modification.

  1. Modification of common\models\User.php

Open User.php.

Comment the original code, add with new line of code.

public static function findIdentityByAccessToken($token, $type = null)
{
// throw new NotSupportedException(‘“findIdentityByAccessToken” is not implemented.’); //original code
return static::findOne([‘auth_key’ => $token, ‘status’ => self::STATUS_ACTIVE]); //new code
}

In this function, we only allow access from client who supply $token when status of the user for the token provided is STATUS_ACTIVE.

  1. Modify the End-point

Got to your frontend\module\api\controllers. Open a SAMPLE_CONTROLLER.php file.

add a new line at the top.

use yii\filters\auth\QueryParamAuth;

Add a new block of code behavior within your controller class

public function behaviors(){
$behaviors = parent::behaviors();

  $behaviors['authenticator'] = [
    'class'=> QueryParamAuth::className(),
    'only' => [
            'update',  'list' //to authorize some specific action in the end-point app
        ]
  ];
  
  return $behaviors;
}

This is complete code of our controller class.

class EventController extends \yii\web\Controller
{
public $enableCsrfValidation = false; //use this to prevent csrf error

public function behaviors(){
  $behaviors= parent::behaviors();
  
  $behaviors['authenticator'] = [
    'class'=> QueryParamAuth::className(),
    'only' => [
            'entry',  'update' //to authorize some specific action end-points
        ]
  ];
  
  return$behaviors;
}

public function actionList()
{

    \Yii::$app->response->format = Response::FORMAT_JSON;

    $query = new Query; 
    $query->select([
                    'acc_event_list.event_type AS Type', 
                    'acc_event_list.level AS Level', 
                    'acc_event_list.begin_date AS BeginDate', 
                    'acc_event_list.end_date AS EndDate', 
                    'acc_event_list.title AS Title', 
                    'acc_event_list.city AS City',
                    'acc_event_list.country AS Country',
                    'acc_event_list.status AS Status',
                    'acc_event_list.publish AS Publish'
                    ])  
            ->from('acc_event_list')
            ->where(['status'=>'Approved'])
            ->andWhere(['>=', 'begin_date', date('Y-m-d')])
            ->orderBy('acc_event_list.begin_date DESC')
            ->limit(50);
                    
    $command = $query->createCommand();
    $event = $command->queryAll();
    
    $count = count($event);
    
    if($count>0){
        return array('status'=>true, 'results'=>$event);
    }
            
}

public function actionUpdate()
{

    \Yii::$app->response->format = \yii\web\Response::FORMAT_JSON;     

     $attributes = \yii::$app->request->post(); 
   
     $kueri = Event::find()->where(['source' => $attributes['source'], 'id'=> $attributes['id']])->one();

    if(!empty($kueri))
    {
           $kueri->attributes = \yii::$app->request->post();
           
           $kueri->save();
           
           return array('status' => true, 'message'=> 'Event data updated successfully');
    }
    else
    {
       return array('status'=>false, 'message'=> 'There is an error '.$model->getErrors());
    }
}    

}

  1. Modify Client Address

If the above modifications are in the end-point app, now we go to the client app.

Assume our client is lie in the main index.php, go to frontend\controllers (it is Yii2 app advance too). Open SiteController.php.

Go to public function Index block.

Put this line at the top

use yii\httpclient\Client; //put it in the top

Then modify action index controller.

<?php

public function actionIndex()
{
$client_1 = new Client();
$response_3 = $client_1->createRequest()
->setUrl('https://WEB_ADDRESS/api/event/list.html?access-token=‘AUTH_KEY’)
->send();

    $data_3 = yii\helpers\Json::decode($response_3->content);
    
    if ($response_3->isOk && !empty($data_3)) {
        $hasil_3 = $data_3['results'];
        
        $dataProvider_3 = new ArrayDataProvider([
            'allModels' => $hasil_3,
            'pagination' => [
                'pageSize' => 10,
            ],
        ]);
    } 
    else{
        $dataProvider_3 = null;
    }
    
    return $this->render('index', 
    [
        'dataProvider' => $dataProvider,
        'dataProvider_3' => $dataProvider_3,
    ]);
}

?>

The special in this block is AUTH_KEY. It is plain characters copied from auth_key colomn of user table of end-point database (Attention: Not the client app database). For it just go to user table, open the row and copy the auth_key data, like this ‘$2y$13$ksbHY4imWvGmH2ANgxa6nOdsEKrNGu/u2fu6MYdLKg9YqT320vm82’. Then change AUTH_KEY with just paste it (do not try to re-type it!).

Please note that in the common\models\User.php we mentioned $token parameter but in this client page we mentioned ‘access-token’.

  1. Modify client view address.

Finally go to frontend\views\site, and open index.php file.

Add block

<?php

echo GridView::widget([
‘dataProvider’ => $dataProvider_3,
‘summary’ => ‘’,
‘columns’ => [
[
‘class’ => ‘yii\grid\SerialColumn’,
‘headerOptions’ => [‘style’ => ‘width:5%’, ‘class’ => ‘text-center’],
‘contentOptions’ => [‘style’ => ‘width:5%’, ‘class’ => ‘text-center’],
],

            [
                  'label' => 'Title',
                  'headerOptions' => ['style' => 'width:30%', 'class' => 'text-left'],
                  'contentOptions' => ['class' => 'text-left'],
                  'format' => 'raw',
                  'value' => function($model){
                    return $model['Title'];
                  }
            ],

            [
                  'label' => 'Type, Level',
                  'headerOptions' => ['style' => 'width:30%', 'class' => 'text-left'],
                  'contentOptions' => ['class' => 'text-left'],
                  'format' => 'raw',
                  'value' => function($model){
                    return $model['Level'].' '.$model['Type'];
                  }
            ],
        [
            'label' => 'Date',
            'headerOptions' => ['style' => 'width:20%', 'class' => 'text-center'],
            'contentOptions' => ['class' => 'text-left'],
            'format' => 'raw',
            'value' => function($model){
                if($model['BeginDate'] != $model['EndDate']){
                    $date = Yii::$app->formatter->asDate($model['BeginDate'], 'php:M d, Y').' - '.Yii::$app->formatter->asDate($model['EndDate'], 'php:M d, Y');
                }
                else{
                    $date = Yii::$app->formatter->asDate($model['BeginDate'], 'php:M d, Y');
                }
                
              return $date;
            }
        ],
                          
         [
            'label' => 'City, Country',
            'headerOptions' => ['style' => 'width:30%', 'class' => 'text-left'],
            'contentOptions' => ['class' => 'text-left'],
            'format' => 'raw',
            'value' => function($model){
              return  $model['City'].', '.$model['Country'];
            }
           ],
        ],
        ]); 
        
        ?>

That’s it. Good luck.

1 Like