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:
- config\main.php
- common\models\User.php
- end-point
- client controller
- client view address
Letâs jump into the detail.
- 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.
- 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.
- 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());
}
}
}
- 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â.
- 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.