Yii2.0 restful API certification tutorial

Time:2020-2-13

Certification introduction

Unlike web applications,RESTful APIsUsually stateless, which means that it should not be usedsessionsorcookies, so each request should be accompanied by some kind of authorization certificate, because the user authorization status may not passsessionsorcookiesMaintenance, a common practice is to send a secret for each requestaccess tokenTo authenticate users becauseaccess tokenIt can uniquely identify and authenticate users,APIRequest should be passedHTTPSTo prevent man in the middle (mitm) man in the middle attack.

Authentication method

  • HTTP basic authentication: access token is sent as a user name. When it is used in access token, it can be safely used in the scenario of API user. For example, the API user is a program running on a server.
  • Request parameters:access tokenSend as API URL request parameter, for examplehttps://example.com/users?access-token=xxxxxxxx, because most servers save request parameters to the log, this method is mainly used forJSONPRequest because it cannot be sent using HTTP headersaccess token
  • OAuth 2: the user obtains the authentication server based onOAuth2Agreementaccess token, and then throughHTTP Bearer TokensSend toAPIThe server.

The above is a brief introduction from the authoritative guide of Yii framework 2.0

Implementation steps

We all knowYii2.0The default authentication classes areUser, both front and back platforms share the same authentication class, so we need toAPIThe authentication class is separated separately, and before, after and API are separated,
Next to the previous chapter: (the default user data table is temporarily used here. Please separate different data tables for authentication in the formal environment.)

Preparation conditions

Following the last paragraphUserData table, we need to add anotheraccess_tokenField,

  1. Add directly to your databaseaccess_tokenField.
  2. How to use data migration

Enter the project root directory to open the console and enter the following command:

php yii migrate/create add_access_token_to_user

openYour project directory / console / migrations / m180704 ABCD add ABCD access ABCD token ABCD to ABCD user.phpAmend the following:

    public function safeUp()
    {
        $this->addColumn('user', 'access_token', $this->string());
    }

    public function safeDown()
    {
        $this->dropColumn('user', 'access_token');
    }

Execute migration command

php yii migrate

The browser opens the frontend page of the front desk directory, and click register account to register an account first

To configure

openapi\config\main.php

To configureuserApplication components:

*Set the 'identityclass' attribute to which authentication class
*Set the 'enablesession' property to 'false'`
*Set the 'enableautologin' property to 'true'`

takesessionComponent commented out or deleted

'user' => [
            'identityClass' => 'api\models\User',
            'enableAutoLogin' => true,
            'enableSession'=>false,
            //'identityCookie' => ['name' => '_identity-backend', 'httpOnly' => true],
        ],
//'session' => [ // this is the name of the session cookie used for login on the backend
//            'name' => 'advanced-backend',
//        ],

To writeapi\models\User.phpImplement authentication class, inheritIdentityInterface

takecommon\models\UserClass copy toapi\models\Under directory, modify the namespace toapi\models

<?php
namespace api\models;

use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
...
class User extends ActiveRecord implements IdentityInterface
{
    ...
    ...
}

takecommon\models\LoginForm.phpClass copy toapi\models\Under the directory, modify the namespace and override the login method:

<?php
namespace api\models;

use Yii;
use yii\base\Model;
...
...

public function login()
{
    if ($this->validate()) {
        $access_token=$this->_user->generateAccessToken();
        $this->_user->save();
        return $access_token;
    } else {
        return false;
    }
}

The code above adds agenerateAccessToken()Method, so we arrivedapi\models\User.phpAdd this method to

namespace api\models;

use Yii;
use yii\base\NotSupportedException;
use yii\behaviors\TimestampBehavior;
use yii\db\ActiveRecord;
use yii\web\IdentityInterface;
...
...
class User extends ActiveRecord implements IdentityInterface
{
    ...
    ...
    
    /**
     *Generate accesstoken string
     * @return string
     * @throws \yii\base\Exception
     */
    public function generateAccessToken()
    {
        $this->access_token=Yii::$app->security->generateRandomString();
        return $this->access_token;
    }
}

Next, open the previousUserController write login method

use api\models\LoginForm;
...
... // omit some code


/**
 * landing
 * @return array
 * @throws \yii\base\Exception
 * @throws \yii\base\InvalidConfigException
 */
public function actionLogin()
{
    $model = new LoginForm();
    if ($model->load(Yii::$app->getRequest()->getBodyParams(), '') && $model->login()) {
        return [
            'access_token' => $model->login(),
        ];
    } else {
        return $model->getFirstErrors();
    }
}
...

Finally, add a new URL rule

openapi\config\main.phpmodifycomponentsProperty, add the following code:

'urlManager' => [
    'enablePrettyUrl' => true,
    'enableStrictParsing' => true,
    'showScriptName' => false,
    'rules' => [
        ['class' => 'yii\rest\UrlRule', 
            'controller' => 'user',
            'extraPatterns'=>[
                'POST login'=>'login',
            ],
        ],
    ],
]

Testing with a debugging toolhttp://youdomain/users/loginRemember thatPOSTRequest to send ifPOSTMANIf you have any questions, please specifyContent-Type:application/x-www-form-urlencoded

OK, if there is no accident, I believe you can receive an access_token. The next step is how to use the token, how to maintain the authentication state, and if you do not carry the token, you will not be able to access it. Return to 401

Maintain certification status

There are only two steps to achieve authentication:

  1. In yoursRESTConfiguration in controller classauthenticatorBehavior to specify which authentication method to use
  2. Implement the yiiwebidentityinterface:: findidentitybyaccesstoken() – detail) method in your user identity class class

Next, we focus on these two steps:

Add a rest controller

  • Because I haven’t designed any other data sheets here, we still use themUserData sheet
  1. stayapi\controllers\Add a new controller namedArticleControllerAnd inherityii\rest\ActiveController, configure authentication mode code: the code is as follows:
<?php
namespace api\controllers;

use yii\rest\ActiveController;
use Yii;
use yii\filters\auth\CompositeAuth;
use yii\filters\auth\HttpBasicAuth;
use yii\filters\auth\HttpBearerAuth;
use yii\filters\auth\QueryParamAuth;

class ArticleController extends ActiveController
{
    public $modelClass = 'api\models\User';
    public function behaviors()
    {
        $behaviors = parent::behaviors();
        $behaviors['authenticator'] = [
            'class' => CompositeAuth::className(),
            'authMethods' => [
                HttpBasicAuth::className(),
                HttpBearerAuth::className(),
                QueryParamAuth::className(),
            ],
        ];
        return $behaviors;
    }
}

Note: this controller is not a real article, but a user

  1. RealizationfindIdentityByAccessToken()Method:

openapi\models\User.phpRewritefindIdentityByAccessToken()Method

...
...
class User extends ActiveRecord implements IdentityInterface
{
    ...
    ...
    
    public static function findIdentityByAccessToken($token, $type = null)
    {
        return static::findOne(['access_token' => $token]);
    }
    ...
}
  1. Add routing rules for the newly added controller (PS: it seems that there is one more step…)

modifyapi\config\main.php

'urlManager' => [
    'enablePrettyUrl' => true,
    'enableStrictParsing' => true,
    'showScriptName' => false,
    'rules' => [
        ['class' => 'yii\rest\UrlRule',
            'controller' => 'user',
            'extraPatterns'=>[
                'GET send-email'=>'send-email'
                'POST login'=>'login',
            ],
        ],
        ['class' => 'yii\rest\UrlRule',
            'controller' => 'article',
            'extraPatterns'=>[

            ],
        ],
    ],
]

Next visit your domain namehttp://youdomain/articles, is 401 returned without any parameters?

OK, here are two ways of access, one is URL access, the other is throughheaderTo carry

  1. http://youdomain/articles?acc…
  2. transmitheaderHeader information
Authorization:Bearer y3XWtwWaxqCEBDoE-qzZk0bCp3UKO920

Notice that there is a space between bearer and your token. Many students have touched it many times

Well, the yii2.0-based restful certification is over,

For more complete functions, please move to official documents
Authorization validation
In addition, there’s speed verification. Let’s find out
In addition, if you can’t read or write well, please moveWei XiTeacher’s video course, I follow all the contentTeacher Wei XiLearned
Wei Xi teaches you how to learn

After writing the authentication, it is found that the data returned by our interface is not very intuitive. In real life, it is usually not so. We may return some specific formats

Custom response content

openapi\config\main.phpstaycomponentsAdd the following contents to the array


'response' => [
    'class' => 'yii\web\Response',
    'on beforeSend' => function ($event) {
        $response = $event->sender;
        $response->data = [
            'success' => $response->isSuccessful,
            'code' => $response->getStatusCode(),
            'message' => $response->statusText,
            'data' => $response->data,
        ];
        $response->statusCode = 200;
    },
],

The status code here is set to 200, which can be configured separately. If the login password is wrong or other, we can use it in the controller as follows:

$response = Yii::$app->response;
    $response->setStatusCode(422);
    return [
        'errmsg' = > 'wrong user name or password!'
    ];

Due to the limited level, it is inevitable that there are mistakes. Please give me some advice and I will be grateful