Попытка реализовать отдельный компонент для oAuth авторизации в свой же API. Не тестировал, не проверял работу, просто пушнул, чтобы потом продолжить в дргуом месте.

This commit is contained in:
ErickSkrauch
2016-08-04 01:07:21 +03:00
parent 71d9511d8e
commit 26b37c2f6b
13 changed files with 241 additions and 8 deletions

View File

@@ -0,0 +1,22 @@
<?php
namespace api\components\ApiUser;
use common\models\OauthAccessToken;
use yii\rbac\CheckAccessInterface;
class AuthChecker implements CheckAccessInterface {
/**
* @inheritdoc
*/
public function checkAccess($token, $permissionName, $params = []) : bool {
/** @var OauthAccessToken|null $accessToken */
$accessToken = OauthAccessToken::findOne($token);
if ($accessToken === null) {
return false;
}
return $accessToken->getScopes()->exists($permissionName);
}
}

View File

@@ -0,0 +1,19 @@
<?php
namespace api\components\ApiUser;
use yii\web\User as YiiUserComponent;
/**
* @property Identity|null $identity
*
* @method Identity|null getIdentity()
*/
class Component extends YiiUserComponent {
public $identity = Identity::class;
public $enableSession = false;
public $loginUrl = null;
}

View File

@@ -0,0 +1,81 @@
<?php
namespace api\components\ApiUser;
use common\models\Account;
use common\models\OauthAccessToken;
use common\models\OauthClient;
use common\models\OauthSession;
use yii\base\NotSupportedException;
use yii\web\IdentityInterface;
use yii\web\UnauthorizedHttpException;
/**
* @property Account $account
* @property OauthClient $client
* @property OauthSession $session
* @property OauthAccessToken $accessToken
*/
class Identity implements IdentityInterface {
/**
* @var OauthAccessToken
*/
private $_accessToken;
/**
* @inheritdoc
*/
public static function findIdentityByAccessToken($token, $type = null) {
/** @var OauthAccessToken|null $model */
$model = OauthAccessToken::findOne($token);
if ($model === null) {
throw new UnauthorizedHttpException('Incorrect token');
} elseif ($model->isExpired()) {
throw new UnauthorizedHttpException('Token expired');
}
return new static($model);
}
private function __construct(OauthAccessToken $accessToken) {
$this->_accessToken = $accessToken;
}
public function getAccount() : Account {
return $this->getSession()->account;
}
public function getClient() : OauthClient {
return $this->getSession()->client;
}
public function getSession() : OauthSession {
return $this->_accessToken->session;
}
public function getAccessToken() : OauthAccessToken {
return $this->_accessToken;
}
/**
* Этот метод используется для получения пользователя, к которому привязаны права.
* У нас права привязываются к токенам, так что возвращаем именно его id.
* @inheritdoc
*/
public function getId() {
return $this->_accessToken->access_token;
}
public function getAuthKey() {
throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
}
public function validateAuthKey($authKey) {
throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
}
public static function findIdentity($id) {
throw new NotSupportedException('This method used for cookie auth, except we using Bearer auth');
}
}

View File

@@ -26,6 +26,12 @@ use yii\web\User as YiiUserComponent;
*/
class Component extends YiiUserComponent {
public $enableSession = false;
public $loginUrl = null;
public $identityClass = AccountIdentity::class;
public $secret;
public $expirationTimeout = 3600; // 1h

View File

@@ -15,11 +15,11 @@ return [
'components' => [
'user' => [
'class' => \api\components\User\Component::class,
'identityClass' => \api\models\AccountIdentity::class,
'enableSession' => false,
'loginUrl' => null,
'secret' => $params['userSecret'],
],
'apiUser' => [
'class' => \api\components\ApiUser\Component::class,
],
'log' => [
'traceLevel' => YII_DEBUG ? 3 : 0,
'targets' => [

View File

@@ -0,0 +1,31 @@
<?php
namespace api\controllers;
use Yii;
use yii\filters\auth\HttpBearerAuth;
/**
* Поведения:
* @mixin \yii\filters\ContentNegotiator
* @mixin \yii\filters\VerbFilter
* @mixin HttpBearerAuth
*/
class ApiController extends \yii\rest\Controller {
public function behaviors() {
$parentBehaviors = parent::behaviors();
// Добавляем авторизатор для входа по Bearer токенам
$parentBehaviors['authenticator'] = [
'class' => HttpBearerAuth::class,
'user' => Yii::$app->apiUser,
];
// xml нам не понадобится
unset($parentBehaviors['contentNegotiator']['formats']['application/xml']);
// rate limiter здесь не применяется
unset($parentBehaviors['rateLimiter']);
return $parentBehaviors;
}
}

View File

@@ -2,6 +2,7 @@
namespace api\controllers;
use api\traits\ApiNormalize;
use Yii;
use yii\filters\auth\HttpBearerAuth;
/**
@@ -18,6 +19,7 @@ class Controller extends \yii\rest\Controller {
// Добавляем авторизатор для входа по jwt токенам
$parentBehaviors['authenticator'] = [
'class' => HttpBearerAuth::class,
'user' => Yii::$app->getUser(),
];
// xml нам не понадобится

View File

@@ -0,0 +1,43 @@
<?php
namespace api\controllers;
use common\models\OauthScope;
use Yii;
use yii\filters\AccessControl;
use yii\helpers\ArrayHelper;
class IdentityInfoController extends ApiController {
public function behaviors() {
return ArrayHelper::merge(parent::behaviors(), [
'access' => [
'class' => AccessControl::class,
'rules' => [
[
'actions' => ['index'],
'allow' => true,
'roles' => ['@'],
],
],
],
]);
}
public function actionIndex() {
$account = Yii::$app->apiUser->getIdentity()->getAccount();
$response = [
'id' => $account->id,
'uuid' => $account->uuid,
'registeredAt' => $account->created_at,
'profileLink' => $account->getProfileLink(),
'preferredLanguage' => $account->lang,
];
if (Yii::$app->apiUser->can(OauthScope::ACCOUNT_EMAIL)) {
$response['email'] = $account->email;
}
return $response;
}
}