Logo Questions Linux Laravel Mysql Ubuntu Git Menu
 

Yii2 REST Simplify BasicAuth

Tags:

rest

php

api

yii

yii2

I'm impressed with how simple it was to create a REST api in Yii2. However, i'm having a little trouble understanding the Basic Authentication. My needs are utterly simple and i'd like my solution to follow suit.

I need Basic token authentication here. I'm not even against hardcoding it for now, but here's what i've done thus far.

I have database table to hold my singular token ApiAccess(id, access_token)

ApiAccess.php - Model - NOTE: IDE shows syntax error on this first line

 class ApiAccess extends base\ApiAccessBase implements IdentityInterface
 {
   public static function findIdentityByAccessToken($token, $type = null)
   {
     return static::findOne(['access_token' => $token]);
   }
 }

Module.php - in init() function

 \Yii::$app->user->enableSession = false;

I made an ApiController that each subsequent noun extends

ApiController.php

 use yii\rest\ActiveController;
 use yii\filters\auth\HttpBasicAuth;
 use app\models\db\ApiAccess;

 class ApiController extends ActiveController
 {
   public function behaviors()
   {
      $behaviors = parent::behaviors();
      $behaviors['authenticator'] = [
        'class' => HttpBasicAuth::className(),
      ];
     return $behaviors;
   }
 }

As it stands, accessing an api endpoint in the browser prompts for a username and password. Request via REST Client displays access error.

How do I properly tie HttpBasicAuth to my ApiAccess model?

OR

How do I hardcode an api access token? (First option is obviously best)

like image 657
Joshua Avatar asked Apr 10 '15 17:04

Joshua


1 Answers

Let's watch and try to understand "yii" way basic auth for REST.

1st. When you adding behavior to your REST controller, you enabling basic auth:

$behaviors['authenticator'] = [
    'class' => HttpBasicAuth::className(),
  ];

As you did. What does it mean? It means that your application will parse your authorization header. It looks like:

Authorization : Basic base64(user:password)

Here is a trick for yii2. If you look at code more carefully, you will see that yii uses access_token from user field, so your header should look like:

Authorization : Basic base64(access_token:)

You can parse this header by your own, if you want to change this behavior:

$behaviors['authenticator'] = [
            'class' => HttpBasicAuth::className(),
            'auth' => [$this, 'auth']
        ];
....
public function auth($username, $password)
    {
        return \app\models\User::findOne(['login' => $username, 'password' => $password]);
    }

2nd thing to do. You must implement findIdentityByAccessToken() function from identityInterface. Why your IDE complaining?

class User extends ActiveRecord implements IdentityInterface

Here's how your user class declaration should look.

From your implementation and structure:

public static function findIdentityByAccessToken($token, $type = null)
   {
     return static::findOne(['access_token' => $token]);
   }

you not returning object of class which implements identity interface.

How to make it properly? Add column access_token to your users table, and return back your user model (you can look how it must look here - https://github.com/yiisoft/yii2-app-advanced/blob/master/common/models/User.php) If you do this - default code will work with your findIdentityByAccessToken() implementation.

If you don't want to add field to users table - make new one with user_id,access_token fields. Then your implementation should look like:

public static function findIdentityByAccessToken($token, $type = null)
   {
     $apiUser = ApiAccess::find()
        ->where(['access_token' => $token])
        ->one();
     return static::findOne(['id' => $apiUser->user_id, 'status' => self::STATUS_ACTIVE]);
   }

Hope i could cover all of your questions.

like image 134
ineersa Avatar answered Sep 27 '22 20:09

ineersa