From 3f97cb7c04f8cada8fa93ad74067231b13c88b45 Mon Sep 17 00:00:00 2001 From: kirill Date: Wed, 28 Jul 2021 18:15:38 +0300 Subject: [PATCH] add api authentication --- common/models/User.php | 35 ++++++++-- ...41557_add_access_columns_to_user_table.php | 21 ++++++ frontend/config/main.php | 12 ++++ .../api/controllers/UserController.php | 57 +++++++++++++++ frontend/modules/api/models/LoginForm.php | 70 +++++++++++++++++++ 5 files changed, 189 insertions(+), 6 deletions(-) create mode 100644 console/migrations/m210708_141557_add_access_columns_to_user_table.php create mode 100644 frontend/modules/api/controllers/UserController.php create mode 100644 frontend/modules/api/models/LoginForm.php diff --git a/common/models/User.php b/common/models/User.php index d706022..1658563 100755 --- a/common/models/User.php +++ b/common/models/User.php @@ -3,10 +3,10 @@ namespace common\models; use Yii; -use yii\base\NotSupportedException; use yii\behaviors\TimestampBehavior; use yii\db\ActiveRecord; use yii\web\IdentityInterface; +use yii\web\UnauthorizedHttpException; /** * User model @@ -64,14 +64,25 @@ class User extends ActiveRecord implements IdentityInterface return static::findOne(['id' => $id, 'status' => self::STATUS_ACTIVE]); } - /** - * {@inheritdoc} - */ - public static function findIdentityByAccessToken($token, $type = null) + public function generateAccessToken() { - throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); + $this->access_token = Yii::$app->security->generateRandomString(); + return $this->access_token; } + public static function findIdentityByAccessToken($token, $type = null) + { + $user = static::find()->where(['access_token' => $token, 'status' => self::STATUS_ACTIVE])->one(); + if (!$user) { + return false; + } + if (strtotime($user->access_token_expired_at) < time()) { + throw new UnauthorizedHttpException('the access - token expired ', -1); + } else { + return $user; + } + + } /** * Finds user by username * @@ -186,4 +197,16 @@ class User extends ActiveRecord implements IdentityInterface { $this->password_reset_token = null; } + + public function beforeSave($insert) + { + if (parent::beforeSave($insert)) { + if ($this->isNewRecord) { + $this->auth_key = Yii::$app->security->generateRandomString(); + } + return true; + } + return false; + } + } diff --git a/console/migrations/m210708_141557_add_access_columns_to_user_table.php b/console/migrations/m210708_141557_add_access_columns_to_user_table.php new file mode 100644 index 0000000..142cde5 --- /dev/null +++ b/console/migrations/m210708_141557_add_access_columns_to_user_table.php @@ -0,0 +1,21 @@ +addColumn('user', 'access_token', $this->string()); + $this->addColumn('user', 'access_token_expired_at', $this->dateTime()); + } + + public function safeDown() + { + $this->dropColumn('user', 'access_token'); + $this->dropColumn('user', 'access_token_expired_at'); + } +} diff --git a/frontend/config/main.php b/frontend/config/main.php index 7b2da72..7899e29 100755 --- a/frontend/config/main.php +++ b/frontend/config/main.php @@ -15,6 +15,15 @@ return [ 'modules' => [ 'api' => [ + 'components' => [ + 'user' => [ + 'identityClass' => 'frontend\modules\api\models\User', + 'enableAutoLogin' => true, + 'enableSession' => false, + 'class' => 'frontend\modules\api\models\User', + //'identityCookie' => ['name' => '_identity-api', 'httpOnly' => true], + ], + ], 'class' => 'frontend\modules\api\Api', ], 'access' => [ @@ -32,6 +41,9 @@ return [ 'request' => [ 'csrfParam' => '_csrf-frontend', 'baseUrl' => '', + 'parsers' => [ + 'application/json' => 'yii\web\JsonParser', + ], ], 'user' => [ 'identityClass' => 'common\models\User', diff --git a/frontend/modules/api/controllers/UserController.php b/frontend/modules/api/controllers/UserController.php new file mode 100644 index 0000000..7a6c2a4 --- /dev/null +++ b/frontend/modules/api/controllers/UserController.php @@ -0,0 +1,57 @@ + ContentNegotiator::class, + 'formats' => [ + 'application/json' => Response::FORMAT_JSON, + ], + ], + 'authenticatior' => [ + 'class' => QueryParamAuth::class, //implement access token authentication + 'except' => ['login'], // no need to verify the access token method, pay attention to distinguish between $noAclLogin + ] + ]); + } + + public function actions() + { + $action = parent::actions(); // TODO: Change the autogenerated stub + unset($action['index']); + unset($action['create']); + unset($action['update']); + unset($action['delete']); + } + + + public function actionLogin() + { + $model = new LoginForm(); + if ($model->load(Yii::$app->getRequest()->getBodyParams(), '') && $model->login()) { + return [ + 'access_token' => $model->login(), + ]; + } else { + throw new BadRequestHttpException(json_encode($model->errors)); + } + } +} diff --git a/frontend/modules/api/models/LoginForm.php b/frontend/modules/api/models/LoginForm.php new file mode 100644 index 0000000..30a75ec --- /dev/null +++ b/frontend/modules/api/models/LoginForm.php @@ -0,0 +1,70 @@ +hasErrors()) { + $user = $this->getUser(); + if (!$user || !$user->validatePassword($this->password)) { + $this->addError($attribute, 'Incorrect username or password.'); + } + } + } + + public function login() + { + if ($this->validate()) { + //return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600 * 24 * 30 : 0); + if ($this->getUser()) { + $access_token = $this->_user->generateAccessToken(); + $this->_user->access_token_expired_at = date('Y-m-d', time() + static::EXPIRE_TIME); + $this->_user->save(); + Yii::$app->user->login($this->_user, static::EXPIRE_TIME); + return $access_token; + } + } + return false; + } + + protected function getUser() + { + if ($this->_user === null) { + $this->_user = User::findByUsername($this->username); + } + + return $this->_user; + } +}