mirror of
https://github.com/elyby/accounts.git
synced 2025-05-31 14:11:46 +05:30
Все классы, отвечающие за oAuth передвинуты в компоненты API, освежён код, поправлены неймспейсы
This commit is contained in:
88
api/components/OAuth2/Storage/AccessTokenStorage.php
Normal file
88
api/components/OAuth2/Storage/AccessTokenStorage.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
namespace api\components\OAuth2\Storage;
|
||||
|
||||
use api\components\OAuth2\Entities\AccessTokenEntity;
|
||||
use common\models\OauthAccessToken;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity as OriginalAccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
use League\OAuth2\Server\Storage\AbstractStorage;
|
||||
use League\OAuth2\Server\Storage\AccessTokenInterface;
|
||||
use yii\db\Exception;
|
||||
|
||||
class AccessTokenStorage extends AbstractStorage implements AccessTokenInterface {
|
||||
|
||||
private $cache = [];
|
||||
|
||||
/**
|
||||
* @param string $token
|
||||
* @return OauthAccessToken|null
|
||||
*/
|
||||
private function getTokenModel($token) {
|
||||
if (!isset($this->cache[$token])) {
|
||||
$this->cache[$token] = OauthAccessToken::findOne($token);
|
||||
}
|
||||
|
||||
return $this->cache[$token];
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function get($token) {
|
||||
$model = $this->getTokenModel($token);
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var SessionStorage $sessionStorage */
|
||||
$sessionStorage = $this->server->getSessionStorage();
|
||||
|
||||
$token = new AccessTokenEntity($this->server);
|
||||
$token->setId($model->access_token);
|
||||
$token->setExpireTime($model->expire_time);
|
||||
$token->setSession($sessionStorage->getById($model->session_id));
|
||||
|
||||
return $token;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getScopes(OriginalAccessTokenEntity $token) {
|
||||
$entities = [];
|
||||
foreach($this->getTokenModel($token->getId())->getScopes() as $scope) {
|
||||
$entities[] = (new ScopeEntity($this->server))->hydrate(['id' => $scope]);
|
||||
}
|
||||
|
||||
return $entities;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function create($token, $expireTime, $sessionId) {
|
||||
$model = new OauthAccessToken();
|
||||
$model->access_token = $token;
|
||||
$model->expire_time = $expireTime;
|
||||
$model->session_id = $sessionId;
|
||||
|
||||
if (!$model->save()) {
|
||||
throw new Exception('Cannot save ' . OauthAccessToken::class . ' model.');
|
||||
}
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function associateScope(OriginalAccessTokenEntity $token, ScopeEntity $scope) {
|
||||
$this->getTokenModel($token->getId())->getScopes()->add($scope->getId());
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function delete(OriginalAccessTokenEntity $token) {
|
||||
$this->getTokenModel($token->getId())->delete();
|
||||
}
|
||||
|
||||
}
|
88
api/components/OAuth2/Storage/AuthCodeStorage.php
Normal file
88
api/components/OAuth2/Storage/AuthCodeStorage.php
Normal file
@@ -0,0 +1,88 @@
|
||||
<?php
|
||||
namespace api\components\OAuth2\Storage;
|
||||
|
||||
use api\components\OAuth2\Entities\AuthCodeEntity;
|
||||
use common\components\redis\Key;
|
||||
use common\components\redis\Set;
|
||||
use League\OAuth2\Server\Entity\AuthCodeEntity as OriginalAuthCodeEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
use League\OAuth2\Server\Storage\AbstractStorage;
|
||||
use League\OAuth2\Server\Storage\AuthCodeInterface;
|
||||
|
||||
class AuthCodeStorage extends AbstractStorage implements AuthCodeInterface {
|
||||
|
||||
public $dataTable = 'oauth_auth_codes';
|
||||
|
||||
public $ttl = 3600; // 1h
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function get($code) {
|
||||
$result = (new Key($this->dataTable, $code))->getValue();
|
||||
if (!$result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
if ($result['expire_time'] < time()) {
|
||||
return null;
|
||||
}
|
||||
|
||||
/** @var SessionStorage $sessionStorage */
|
||||
$sessionStorage = $this->server->getSessionStorage();
|
||||
|
||||
$entity = new AuthCodeEntity($this->server);
|
||||
$entity->setId($result['id']);
|
||||
$entity->setRedirectUri($result['client_redirect_uri']);
|
||||
$entity->setExpireTime($result['expire_time']);
|
||||
$entity->setSession($sessionStorage->getById($result['session_id']));
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function create($token, $expireTime, $sessionId, $redirectUri) {
|
||||
$payload = [
|
||||
'id' => $token,
|
||||
'expire_time' => $expireTime,
|
||||
'session_id' => $sessionId,
|
||||
'client_redirect_uri' => $redirectUri,
|
||||
];
|
||||
|
||||
(new Key($this->dataTable, $token))->setValue($payload)->expire($this->ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getScopes(OriginalAuthCodeEntity $token) {
|
||||
$result = new Set($this->dataTable, $token->getId(), 'scopes');
|
||||
$response = [];
|
||||
foreach ($result as $scope) {
|
||||
// TODO: нужно проверить все выданные скоупы на их существование
|
||||
$response[] = (new ScopeEntity($this->server))->hydrate(['id' => $scope]);
|
||||
}
|
||||
|
||||
return $response;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function associateScope(OriginalAuthCodeEntity $token, ScopeEntity $scope) {
|
||||
(new Set($this->dataTable, $token->getId(), 'scopes'))->add($scope->getId())->expire($this->ttl);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function delete(OriginalAuthCodeEntity $token) {
|
||||
// Удаляем ключ
|
||||
(new Set($this->dataTable, $token->getId()))->delete();
|
||||
// Удаляем список скоупов для ключа
|
||||
(new Set($this->dataTable, $token->getId(), 'scopes'))->delete();
|
||||
}
|
||||
|
||||
}
|
82
api/components/OAuth2/Storage/ClientStorage.php
Normal file
82
api/components/OAuth2/Storage/ClientStorage.php
Normal file
@@ -0,0 +1,82 @@
|
||||
<?php
|
||||
namespace api\components\OAuth2\Storage;
|
||||
|
||||
use api\components\OAuth2\Entities\ClientEntity;
|
||||
use api\components\OAuth2\Entities\SessionEntity;
|
||||
use common\models\OauthClient;
|
||||
use League\OAuth2\Server\Entity\SessionEntity as OriginalSessionEntity;
|
||||
use League\OAuth2\Server\Storage\AbstractStorage;
|
||||
use League\OAuth2\Server\Storage\ClientInterface;
|
||||
use yii\helpers\StringHelper;
|
||||
|
||||
class ClientStorage extends AbstractStorage implements ClientInterface {
|
||||
|
||||
const REDIRECT_STATIC_PAGE = 'static_page';
|
||||
const REDIRECT_STATIC_PAGE_WITH_CODE = 'static_page_with_code';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function get($clientId, $clientSecret = null, $redirectUri = null, $grantType = null) {
|
||||
$query = OauthClient::find()->andWhere(['id' => $clientId]);
|
||||
if ($clientSecret !== null) {
|
||||
$query->andWhere(['secret' => $clientSecret]);
|
||||
}
|
||||
|
||||
/** @var OauthClient|null $model */
|
||||
$model = $query->one();
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
// TODO: нужно учитывать тип приложения
|
||||
/*
|
||||
* Для приложений типа "настольный" redirect_uri необязателем - он должен быть по умолчанию равен
|
||||
* статичному редиректу на страницу сайта
|
||||
* А для приложений типа "сайт" редирект должен быть всегда.
|
||||
* Короче это нужно учесть
|
||||
*/
|
||||
if ($redirectUri !== null) {
|
||||
if (in_array($redirectUri, [self::REDIRECT_STATIC_PAGE, self::REDIRECT_STATIC_PAGE_WITH_CODE], true)) {
|
||||
// Тут, наверное, нужно проверить тип приложения
|
||||
} else {
|
||||
if (!StringHelper::startsWith($redirectUri, $model->redirect_uri, false)) {
|
||||
return null;
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
$entity = $this->hydrate($model);
|
||||
$entity->setRedirectUri($redirectUri);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getBySession(OriginalSessionEntity $session) {
|
||||
if (!$session instanceof SessionEntity) {
|
||||
throw new \ErrorException('This module assumes that $session typeof ' . SessionEntity::class);
|
||||
}
|
||||
|
||||
/** @var OauthClient|null $model */
|
||||
$model = OauthClient::findOne($session->getClientId());
|
||||
if ($model === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
return $this->hydrate($model);
|
||||
}
|
||||
|
||||
private function hydrate(OauthClient $model) : ClientEntity {
|
||||
$entity = new ClientEntity($this->server);
|
||||
$entity->setId($model->id);
|
||||
$entity->setName($model->name);
|
||||
$entity->setSecret($model->secret);
|
||||
$entity->setRedirectUri($model->redirect_uri);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
}
|
50
api/components/OAuth2/Storage/RefreshTokenStorage.php
Normal file
50
api/components/OAuth2/Storage/RefreshTokenStorage.php
Normal file
@@ -0,0 +1,50 @@
|
||||
<?php
|
||||
namespace api\components\OAuth2\Storage;
|
||||
|
||||
use common\components\redis\Key;
|
||||
use League\OAuth2\Server\Entity\RefreshTokenEntity;
|
||||
use League\OAuth2\Server\Storage\AbstractStorage;
|
||||
use League\OAuth2\Server\Storage\RefreshTokenInterface;
|
||||
|
||||
class RefreshTokenStorage extends AbstractStorage implements RefreshTokenInterface {
|
||||
|
||||
public $dataTable = 'oauth_refresh_tokens';
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function get($token) {
|
||||
$result = (new Key($this->dataTable, $token))->getValue();
|
||||
if (!$result) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$entity = new RefreshTokenEntity($this->server);
|
||||
$entity->setId($result['id']);
|
||||
$entity->setExpireTime($result['expire_time']);
|
||||
$entity->setAccessTokenId($result['access_token_id']);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function create($token, $expireTime, $accessToken) {
|
||||
$payload = [
|
||||
'id' => $token,
|
||||
'expire_time' => $expireTime,
|
||||
'access_token_id' => $accessToken,
|
||||
];
|
||||
|
||||
(new Key($this->dataTable, $token))->setValue($payload);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function delete(RefreshTokenEntity $token) {
|
||||
(new Key($this->dataTable, $token->getId()))->delete();
|
||||
}
|
||||
|
||||
}
|
27
api/components/OAuth2/Storage/ScopeStorage.php
Normal file
27
api/components/OAuth2/Storage/ScopeStorage.php
Normal file
@@ -0,0 +1,27 @@
|
||||
<?php
|
||||
namespace api\components\OAuth2\Storage;
|
||||
|
||||
use api\components\OAuth2\Entities\ScopeEntity;
|
||||
use common\models\OauthScope;
|
||||
use League\OAuth2\Server\Storage\AbstractStorage;
|
||||
use League\OAuth2\Server\Storage\ScopeInterface;
|
||||
|
||||
class ScopeStorage extends AbstractStorage implements ScopeInterface {
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function get($scope, $grantType = null, $clientId = null) {
|
||||
/** @var OauthScope|null $row */
|
||||
$row = OauthScope::findOne($scope);
|
||||
if ($row === null) {
|
||||
return null;
|
||||
}
|
||||
|
||||
$entity = new ScopeEntity($this->server);
|
||||
$entity->setId($row->id);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
}
|
120
api/components/OAuth2/Storage/SessionStorage.php
Normal file
120
api/components/OAuth2/Storage/SessionStorage.php
Normal file
@@ -0,0 +1,120 @@
|
||||
<?php
|
||||
namespace api\components\OAuth2\Storage;
|
||||
|
||||
use api\components\OAuth2\Entities\AuthCodeEntity;
|
||||
use api\components\OAuth2\Entities\SessionEntity;
|
||||
use common\models\OauthSession;
|
||||
use ErrorException;
|
||||
use League\OAuth2\Server\Entity\AccessTokenEntity as OriginalAccessTokenEntity;
|
||||
use League\OAuth2\Server\Entity\AuthCodeEntity as OriginalAuthCodeEntity;
|
||||
use League\OAuth2\Server\Entity\ScopeEntity;
|
||||
use League\OAuth2\Server\Entity\SessionEntity as OriginalSessionEntity;
|
||||
use League\OAuth2\Server\Storage\AbstractStorage;
|
||||
use League\OAuth2\Server\Storage\SessionInterface;
|
||||
use yii\db\ActiveQuery;
|
||||
use yii\db\Exception;
|
||||
|
||||
class SessionStorage extends AbstractStorage implements SessionInterface {
|
||||
|
||||
private $cache = [];
|
||||
|
||||
/**
|
||||
* @param string $sessionId
|
||||
* @return SessionEntity|null
|
||||
*/
|
||||
public function getById($sessionId) {
|
||||
return $this->hydrate($this->getSessionModel($sessionId));
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getByAccessToken(OriginalAccessTokenEntity $accessToken) {
|
||||
/** @var OauthSession|null $model */
|
||||
$model = OauthSession::find()->innerJoinWith([
|
||||
'accessTokens' => function(ActiveQuery $query) use ($accessToken) {
|
||||
$query->andWhere(['access_token' => $accessToken->getId()]);
|
||||
},
|
||||
])->one();
|
||||
|
||||
return $this->hydrate($model);
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function getByAuthCode(OriginalAuthCodeEntity $authCode) {
|
||||
if (!$authCode instanceof AuthCodeEntity) {
|
||||
throw new ErrorException('This module assumes that $authCode typeof ' . AuthCodeEntity::class);
|
||||
}
|
||||
|
||||
return $this->getById($authCode->getSessionId());
|
||||
}
|
||||
|
||||
/**
|
||||
* {@inheritdoc}
|
||||
*/
|
||||
public function getScopes(OriginalSessionEntity $session) {
|
||||
$result = [];
|
||||
foreach ($this->getSessionModel($session->getId())->getScopes() as $scope) {
|
||||
// TODO: нужно проверить все выданные скоупы на их существование
|
||||
$result[] = (new ScopeEntity($this->server))->hydrate(['id' => $scope]);
|
||||
}
|
||||
|
||||
return $result;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function create($ownerType, $ownerId, $clientId, $clientRedirectUri = null) {
|
||||
$sessionId = OauthSession::find()
|
||||
->select('id')
|
||||
->andWhere([
|
||||
'client_id' => $clientId,
|
||||
'owner_type' => $ownerType,
|
||||
'owner_id' => $ownerId,
|
||||
])->scalar();
|
||||
|
||||
if ($sessionId === false) {
|
||||
$model = new OauthSession();
|
||||
$model->client_id = $clientId;
|
||||
$model->owner_type = $ownerType;
|
||||
$model->owner_id = $ownerId;
|
||||
$model->client_redirect_uri = $clientRedirectUri;
|
||||
|
||||
if (!$model->save()) {
|
||||
throw new Exception('Cannot save ' . OauthSession::class . ' model.');
|
||||
}
|
||||
|
||||
$sessionId = $model->id;
|
||||
}
|
||||
|
||||
return $sessionId;
|
||||
}
|
||||
|
||||
/**
|
||||
* @inheritdoc
|
||||
*/
|
||||
public function associateScope(OriginalSessionEntity $session, ScopeEntity $scope) {
|
||||
$this->getSessionModel($session->getId())->getScopes()->add($scope->getId());
|
||||
}
|
||||
|
||||
private function getSessionModel(string $sessionId) : OauthSession {
|
||||
if (!isset($this->cache[$sessionId])) {
|
||||
$this->cache[$sessionId] = OauthSession::findOne($sessionId);
|
||||
}
|
||||
|
||||
return $this->cache[$sessionId];
|
||||
}
|
||||
|
||||
private function hydrate(OauthSession $sessionModel) {
|
||||
$entity = new SessionEntity($this->server);
|
||||
$entity->setId($sessionModel->id);
|
||||
$entity->setClientId($sessionModel->client_id);
|
||||
$entity->setOwner($sessionModel->owner_type, $sessionModel->owner_id);
|
||||
|
||||
return $entity;
|
||||
}
|
||||
|
||||
}
|
Reference in New Issue
Block a user