From 601f0a290bd5bff4b9271e578881cce8367b5ca4 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Tue, 23 Feb 2016 01:22:04 +0300 Subject: [PATCH 1/2] =?UTF-8?q?=D0=98=D0=B7=D0=BC=D0=B5=D0=BD=D1=91=D0=BD?= =?UTF-8?q?=20=D0=B0=D0=BB=D0=B3=D0=BE=D1=80=D0=B8=D1=82=D0=BC=20=D0=B0?= =?UTF-8?q?=D0=B2=D1=82=D0=BE=D1=80=D0=B8=D0=B7=D0=B0=D1=86=D0=B8=D0=B8=20?= =?UTF-8?q?=D0=BD=D0=B0=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE?= =?UTF-8?q?=D0=B2=D0=B0=D0=BD=D0=B8=D0=B5=20jwt=20=D1=82=D0=BE=D0=BA=D0=B5?= =?UTF-8?q?=D0=BD=D0=BE=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/config/main.php | 2 +- api/controllers/AuthenticationController.php | 3 ++- api/models/LoginForm.php | 6 ++--- common/models/Account.php | 27 ++++++++++++++----- composer.json | 5 ++-- environments/dev/api/config/params-local.php | 1 + environments/prod/api/config/params-local.php | 1 + .../codeception/api/functional/LoginCest.php | 2 ++ .../api/unit/models/LoginFormTest.php | 7 ++--- 9 files changed, 34 insertions(+), 20 deletions(-) diff --git a/api/config/main.php b/api/config/main.php index d952cc3..63c9182 100644 --- a/api/config/main.php +++ b/api/config/main.php @@ -14,7 +14,7 @@ return [ 'components' => [ 'user' => [ 'identityClass' => \common\models\Account::class, - 'enableAutoLogin' => true, + 'enableSession' => false, 'loginUrl' => null, ], 'log' => [ diff --git a/api/controllers/AuthenticationController.php b/api/controllers/AuthenticationController.php index d11f7a2..f5f992a 100644 --- a/api/controllers/AuthenticationController.php +++ b/api/controllers/AuthenticationController.php @@ -31,7 +31,7 @@ class AuthenticationController extends Controller { public function actionLogin() { $model = new LoginForm(); $model->load(Yii::$app->request->post()); - if (!$model->login()) { + if (($jwt = $model->login()) === false) { return [ 'success' => false, 'errors' => $this->normalizeModelErrors($model->getErrors()), @@ -40,6 +40,7 @@ class AuthenticationController extends Controller { return [ 'success' => true, + 'jwt' => $jwt, ]; } diff --git a/api/models/LoginForm.php b/api/models/LoginForm.php index e2a794e..18ebed8 100644 --- a/api/models/LoginForm.php +++ b/api/models/LoginForm.php @@ -44,16 +44,14 @@ class LoginForm extends BaseApiForm { } /** - * Logs in a user using the provided username and password. - * - * @return boolean whether the user is logged in successfully + * @return bool|string JWT с информацией об аккаунте */ public function login() { if (!$this->validate()) { return false; } - return Yii::$app->user->login($this->getAccount(), $this->rememberMe ? 3600 * 24 * 30 : 0); + return $this->getAccount()->getJWT(); } /** diff --git a/common/models/Account.php b/common/models/Account.php index f3b0bc4..b043ab6 100644 --- a/common/models/Account.php +++ b/common/models/Account.php @@ -2,6 +2,7 @@ namespace common\models; use common\components\UserPass; +use damirka\JWT\UserTrait; use Yii; use yii\base\InvalidConfigException; use yii\base\NotSupportedException; @@ -34,6 +35,7 @@ use yii\web\IdentityInterface; * @mixin TimestampBehavior */ class Account extends ActiveRecord implements IdentityInterface { + use UserTrait; const STATUS_DELETED = -10; const STATUS_REGISTERED = 0; @@ -64,13 +66,6 @@ class Account extends ActiveRecord implements IdentityInterface { return static::findOne(['id' => $id]); } - /** - * @inheritdoc - */ - public static function findIdentityByAccessToken($token, $type = null) { - throw new NotSupportedException('"findIdentityByAccessToken" is not implemented.'); - } - /** * @param string $email * @return static|null @@ -247,4 +242,22 @@ class Account extends ActiveRecord implements IdentityInterface { return false; } + /** + * @inheritdoc + */ + protected static function getSecretKey() { + return Yii::$app->params['jwtSecret']; + } + + /** + * Getter for "header" array that's used for generation of JWT + * @return array JWT Header Token param, see http://jwt.io/ for details + */ + protected static function getHeaderToken() { + return [ + 'iss' => Yii::$app->request->hostInfo, + 'aud' => Yii::$app->request->hostInfo, + ]; + } + } diff --git a/composer.json b/composer.json index e0d8971..1efe3e9 100644 --- a/composer.json +++ b/composer.json @@ -14,13 +14,14 @@ }, "minimum-stability": "stable", "require": { - "php": ">=5.4.0", + "php": ">=5.6.0", "yiisoft/yii2": ">=2.0.6", "yiisoft/yii2-bootstrap": "*", "yiisoft/yii2-swiftmailer": "*", "ramsey/uuid": "^3.1", "league/oauth2-server": "~4.1.5", - "yiisoft/yii2-redis": "~2.0.0" + "yiisoft/yii2-redis": "~2.0.0", + "damirka/yii2-jwt": "dev-master#be29a5b5d7e7d146c13d4374788e02c54cc04138" }, "require-dev": { "yiisoft/yii2-codeception": "*", diff --git a/environments/dev/api/config/params-local.php b/environments/dev/api/config/params-local.php index d0b9c34..2481e4b 100644 --- a/environments/dev/api/config/params-local.php +++ b/environments/dev/api/config/params-local.php @@ -1,3 +1,4 @@ 'some-long-secret-key', ]; diff --git a/environments/prod/api/config/params-local.php b/environments/prod/api/config/params-local.php index d0b9c34..2481e4b 100644 --- a/environments/prod/api/config/params-local.php +++ b/environments/prod/api/config/params-local.php @@ -1,3 +1,4 @@ 'some-long-secret-key', ]; diff --git a/tests/codeception/api/functional/LoginCest.php b/tests/codeception/api/functional/LoginCest.php index 974bcb5..5b86f2d 100644 --- a/tests/codeception/api/functional/LoginCest.php +++ b/tests/codeception/api/functional/LoginCest.php @@ -101,6 +101,7 @@ class LoginCest { $I->canSeeResponseContainsJson([ 'success' => true, ]); + $I->canSeeResponseJsonMatchesJsonPath('$.jwt'); $I->cantSeeResponseJsonMatchesJsonPath('$.errors'); } @@ -123,6 +124,7 @@ class LoginCest { $I->canSeeResponseContainsJson([ 'success' => true, ]); + $I->canSeeResponseJsonMatchesJsonPath('$.jwt'); $I->cantSeeResponseJsonMatchesJsonPath('$.errors'); } diff --git a/tests/codeception/api/unit/models/LoginFormTest.php b/tests/codeception/api/unit/models/LoginFormTest.php index d3f313e..0f138fb 100644 --- a/tests/codeception/api/unit/models/LoginFormTest.php +++ b/tests/codeception/api/unit/models/LoginFormTest.php @@ -39,25 +39,22 @@ class LoginFormTest extends DbTestCase { $this->specify('get errors and don\'t log in into account with wrong credentials', function () use ($model) { expect('model should not login user', $model->login())->false(); expect('error messages should be set', $model->errors)->notEmpty(); - expect('user should not be logged in', Yii::$app->user->isGuest)->true(); }); } public function testLoginByUsernameCorrect() { $model = $this->createModel('Admin', 'password_0'); $this->specify('user should be able to login with correct username and password', function () use ($model) { - expect('model should login user', $model->login())->true(); + expect('model should login user', $model->login())->notEquals(false); expect('error message should not be set', $model->errors)->isEmpty(); - expect('user should be logged in', Yii::$app->user->isGuest)->false(); }); } public function testLoginByEmailCorrect() { $model = $this->createModel('admin@ely.by', 'password_0'); $this->specify('user should be able to login with correct email and password', function () use ($model) { - expect('model should login user', $model->login())->true(); + expect('model should login user', $model->login())->notEquals(false); expect('error message should not be set', $model->errors)->isEmpty(); - expect('user should be logged in', Yii::$app->user->isGuest)->false(); }); } From 8583edbb928919c06d42268d3efb72e6b62bcec9 Mon Sep 17 00:00:00 2001 From: ErickSkrauch Date: Wed, 24 Feb 2016 01:15:04 +0300 Subject: [PATCH 2/2] =?UTF-8?q?=D0=92=D1=81=D0=B5=20=D0=BA=D0=BE=D0=BD?= =?UTF-8?q?=D1=82=D1=80=D0=BE=D0=BB=D0=BB=D0=B5=D1=80=D1=8B=20=D0=BF=D0=B5?= =?UTF-8?q?=D1=80=D0=B5=D0=B2=D0=B5=D0=B4=D0=B5=D0=BD=D1=8B=20=D0=BD=D0=B0?= =?UTF-8?q?=20=D0=B8=D1=81=D0=BF=D0=BE=D0=BB=D1=8C=D0=B7=D0=BE=D0=B2=D0=B0?= =?UTF-8?q?=D0=BD=D0=B8=D0=B5=20jwt=20=D1=82=D0=BE=D0=BA=D0=B5=D0=BD=D0=BE?= =?UTF-8?q?=D0=B2?= MIME-Version: 1.0 Content-Type: text/plain; charset=UTF-8 Content-Transfer-Encoding: 8bit --- api/controllers/AuthenticationController.php | 6 +++++- api/controllers/Controller.php | 8 ++++++++ api/controllers/OauthController.php | 6 +++++- api/controllers/SignupController.php | 6 +++++- tests/codeception/api/functional/_steps/AccountSteps.php | 3 +++ 5 files changed, 26 insertions(+), 3 deletions(-) diff --git a/api/controllers/AuthenticationController.php b/api/controllers/AuthenticationController.php index f5f992a..f6f5240 100644 --- a/api/controllers/AuthenticationController.php +++ b/api/controllers/AuthenticationController.php @@ -4,11 +4,15 @@ namespace api\controllers; use api\models\LoginForm; use Yii; use yii\filters\AccessControl; +use yii\helpers\ArrayHelper; class AuthenticationController extends Controller { public function behaviors() { - return array_merge(parent::behaviors(), [ + return ArrayHelper::merge(parent::behaviors(), [ + 'authenticator' => [ + 'except' => ['login'], + ], 'access' => [ 'class' => AccessControl::class, 'rules' => [ diff --git a/api/controllers/Controller.php b/api/controllers/Controller.php index 1932f13..b5d716a 100644 --- a/api/controllers/Controller.php +++ b/api/controllers/Controller.php @@ -3,6 +3,7 @@ namespace api\controllers; use api\traits\ApiNormalize; use Yii; +use yii\filters\auth\HttpBearerAuth; /** * @property \common\models\Account|null $account @@ -12,8 +13,15 @@ class Controller extends \yii\rest\Controller { public function behaviors() { $parentBehaviors = parent::behaviors(); + // Добавляем авторизатор для входа по jwt токенам + $parentBehaviors['authenticator'] = [ + 'class' => HttpBearerAuth::className(), + ]; + // xml нам не понадобится unset($parentBehaviors['contentNegotiator']['formats']['application/xml']); + // rate limiter здесь не применяется + unset($parentBehaviors['rateLimiter']); return $parentBehaviors; } diff --git a/api/controllers/OauthController.php b/api/controllers/OauthController.php index c730cf1..0e57144 100644 --- a/api/controllers/OauthController.php +++ b/api/controllers/OauthController.php @@ -14,13 +14,17 @@ use yii\helpers\ArrayHelper; class OauthController extends Controller { public function behaviors() { - return array_merge(parent::behaviors(), [ + return ArrayHelper::merge(parent::behaviors(), [ + 'authenticator' => [ + 'except' => ['validate', 'issue-token'], + ], 'access' => [ 'class' => AccessControl::class, 'rules' => [ [ 'actions' => ['validate', 'issue-token'], 'allow' => true, + 'roles' => ['?'], ], [ 'actions' => ['complete'], diff --git a/api/controllers/SignupController.php b/api/controllers/SignupController.php index bc0191b..5c0cc8c 100644 --- a/api/controllers/SignupController.php +++ b/api/controllers/SignupController.php @@ -5,11 +5,15 @@ use api\models\ConfirmEmailForm; use api\models\RegistrationForm; use Yii; use yii\filters\AccessControl; +use yii\helpers\ArrayHelper; class SignupController extends Controller { public function behaviors() { - return array_merge(parent::behaviors(), [ + return ArrayHelper::merge(parent::behaviors(), [ + 'authenticator' => [ + 'except' => ['register', 'confirm'], + ], 'access' => [ 'class' => AccessControl::class, 'rules' => [ diff --git a/tests/codeception/api/functional/_steps/AccountSteps.php b/tests/codeception/api/functional/_steps/AccountSteps.php index 2b9f618..fc102b7 100644 --- a/tests/codeception/api/functional/_steps/AccountSteps.php +++ b/tests/codeception/api/functional/_steps/AccountSteps.php @@ -11,6 +11,9 @@ class AccountSteps extends FunctionalTester { $route = new LoginRoute($I); $route->login('Admin', 'password_0'); $I->canSeeResponseIsJson(); + $I->canSeeResponseJsonMatchesJsonPath('$.jwt'); + $jwt = $I->grabDataFromResponseByJsonPath('$.jwt')[0]; + $I->amBearerAuthenticated($jwt); } }