Authentication

There are three kinds of authentication:

  • HTTP Basic Auth (the HttpBasicAuth class): This method uses the WWW-Authenticate HTTP header to send the username and password for every request
  • Query parameter (the QueryParamAuth class): This method uses an access token passed as query parameter in the API URL
  • OAuth 2 (the HttpBearerAuth class): This method uses an access token that is obtained by the consumer from an authorization server and sent to the API server via HTTP bearer tokens

Yii supports all the methods mentioned, but we can also easily create a new one.

To enable authentication, follow these steps:

  1. Configure the user application component in the configuration, setting enableSession to false in order to make user authentication status not persistent using a session across requests. Next, set loginUrl to null to show the HTTP 403 error instead of redirecting it to the login page.
  2. Specify which authentication method we want to use, configuring the authenticator behavior in API controller classes.
  3. Implement yiiwebIdentityInterface::findIdentityByAccessToken() in the user identity class.

    Note

    The first step ensures that REST requests are really stateless, but if you need to persist or store session data, you can skip this step.

Step 1 can be configured in api/config/main.php:

    'components' => [
            ...
        'user' => [
            'identityClass' => 'commonmodelsUser',
            'enableSession' => false,
            'loginUrl' => null
        ],
];

Step 2 requires that we extend the behaviors() controller method, specifying a single authenticator:

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

Or we can do this by specifying multiple authenticators:

public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['authenticator'] = [
        'class' => yiifiltersauthCompositeAuth::className(),
        'authMethods' => [
            yiifiltersauthHttpBasicAuth::className(),
            yiifiltersauthHttpBearerAuth::className(),
            yiifiltersauthQueryParamAuth::className(),
        ],
    ];
    return $behaviors;
}

Finally, step 3 requires the implementation of findIdentityByAccessToken() of the identityClass specified in the configuration file.

In a simple scenario, the access token can be stored in a column of the User table and then retrieved:

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

At the end of the configuration, every request will try to authenticate the user in the beforeAction() method of the same controller.

Now, let's take a look at the first authentication method, HTTPBasicAuth. This method requires us to set the auth property to the callable PHP function; if it is not set, the username will be used as the access token passed to the yiiwebUser::loginByAccessToken() method.

The basic implementation of the HttpBasicAuth authentication is:

public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['authenticator'] = [
            'class' => yiifiltersauthHttpBasicAuth::className(),
           'auth' => function($username, $password) {
            // return null or identity interface
    // For example search by username and password
    return commonmodelsUser::findOne(['username' => $username, 'password' => $password);
           }

           /*
           'auth' => [$this, 'httpBasicAuthHandler'],
           */
    ];
    return $behaviors;
}

public function httpBasicAuthHandler($username, $password)
{
    // For example search by username and password
    return commonmodelsUser::findOne(['username' => $username, 'password' => $password]);
}

The callable PHP function stored by the auth property can be represented as an inline function, or as an array, whose first value is the object and the second is the function name to be called, by passing $username and $password parameters.

Check how PHP is running through phpinfo(). If you display CGI/FCGI, then you need to add SetEnvIf Authorization .+ HTTP_AUTHORIZATION=$0 in .htaccess to use HTTP Auth from PHP.

The second authentication method is query parameter, by using the QueryParamAuth class. With this method, a query parameter named access-token must be passed to the URL. Then, it will call the yiiwebuser::loginByAccessToken() method, passing access-token as the first parameter. This function will return an IdentityInterface or null.

The URL parameter name can be changed using tokenParam in the authentication declaration:

public function behaviors()
{
    $behaviors = parent::behaviors();
    $behaviors['authenticator'] = [
            'class' => yiifiltersauthQueryParamAuth::className(),
           'tokenParam' => 'myAccessToken'
    ];
    return $behaviors;
}

With this configuration, the URL must be http://hostname/url?myAccessToken=...

The last authentication method, OAuth 2, requires an authorization server from which we will get the bearer token to pass to the REST API server, which is similar to QueryParamAuth.

Example – using authentication to get a customers list

In this example, we are going to authenticate ourselves by using two methods at the same time: HTTPBasicAuth and QueryParamAuth. When using QueryParamAuth with an access token, we will first call a publically accessible action to get an access token that the user will pass to all the other actions as the query URL parameter.

We will start by creating a new model from the Customer database table and putting it into the common/models folder. Then, we will create a new user in the User database table using, for example, foo as the username and $2a$12$xzGZB29iqBHva4sEYbJeT.pq9g1/VdjoD0S67ciDB30EWSCE18sW6 as the password (this is equivalent to the hashed bar text).

Create a new controller in api/controllers/CustomersController.php that only extends the behaviors() method to implement HTTPBasicAuth and QueryParamAuth:

<?php
namespace apicontrollers;

use yii
estActiveController;
use yiifiltersauthCompositeAuth;
use yiifiltersauthHttpBasicAuth;
use yiifiltersauthQueryParamAuth;

class CustomersController extends ActiveController
{
  public $modelClass = 'commonmodelsCustomer';

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

    $behaviors['authenticator'] = [
      'class' => CompositeAuth::className(),
      'authMethods' => [
        [
          'class' => HttpBasicAuth::className(),
          'auth' => function($username, $password)
          {
            $out = null;
            $user = commonmodelsUser::findByUsername($username);
            if($user!=null)
            {
              if($user->validatePassword($password)) $out = $user;
            }
            return $out;
          }
        ],
        [
           'class' => QueryParamAuth::className(),
        ]
      ]
    ];
      
   return $behaviors;
  }
}

In HTTPBasicAuth, we implement the auth property inside the configuration array by checking $username and then validating the password. If the username and password match each other, it will return the user found or will otherwise be null.

QueryParamAuth, instead, does not need any property other than the class, since we will use access-token as the query parameter name. Nevertheless, to complete this task, we need an action that will return the related user's access token after passing both the username and password.

For this purpose, we will add the actionAccessTokenByUser() method, which looks for the user with the $username and $password parameters passed. If the user already exists, its access_token property will be updated with a random string, so every time we call this action, access_token will change and the previous one will be cancelled:

    public function actionAccessTokenByUser($username, $passwordHash)
    {
        $accessToken = null;
        
        $user = commonmodelsUser::findOne(['username' => $username, 'password_hash' => $passwordHash]);
        if($user!=null)
        {
            $user->access_token = Yii::$app->security->generateRandomString();
            $user->save();
            $accessToken = $user->access_token;
        }        
        return [ 'access-token' => $accessToken ];
    }

Finally, to test HTTPBasicAuth, we need to pass the WWW-Authentication header by calling the http://hostname/yiiadv/api/web/customers/index URL.

If we want to use QueryParamAuth, we need to:

  • Get access-token returned from http://hostname/yiiadv/api/web/customers/access-token-by-user, by passing the username and hashed password
  • Call http://hostname/yiiadv/api/web/customers/index?access-token, by passing the access-token property value received from the previous request

QueryParamAuth calls the findIdentityByAccessToken() function of IdentityInterfaces(the user mode ). So, check that the method is implemented, and if it's not, implement it as follows:

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

Pay attention, as this way of using access tokens allows the use of the REST API with the same credentials for only one client at a time. This is because any time an access-token-by-user is called, a new access-token will be created. Therefore, it should be created a relation one-to-many between users and access-token in order to provide multiple clients with access using the same username/password credentials.

..................Content has been hidden....................

You can't read the all page of ebook, please click here login for view all page.
Reset
3.137.187.233