mirror of
				https://github.com/elyby/accounts.git
				synced 2025-05-31 14:11:46 +05:30 
			
		
		
		
	Первичное портирование логики сервера авторизации с PhalconPHP на Yii2
This commit is contained in:
		
							
								
								
									
										44
									
								
								api/modules/authserver/models/AuthenticateData.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										44
									
								
								api/modules/authserver/models/AuthenticateData.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,44 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\modules\authserver\models;
 | 
			
		||||
 | 
			
		||||
use common\models\MinecraftAccessKey;
 | 
			
		||||
 | 
			
		||||
class AuthenticateData {
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @var MinecraftAccessKey
 | 
			
		||||
     */
 | 
			
		||||
    private $minecraftAccessKey;
 | 
			
		||||
 | 
			
		||||
    public function __construct(MinecraftAccessKey $minecraftAccessKey) {
 | 
			
		||||
        $this->minecraftAccessKey = $minecraftAccessKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getMinecraftAccessKey() : MinecraftAccessKey {
 | 
			
		||||
        return $this->minecraftAccessKey;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function getResponseData(bool $includeAvailableProfiles = false) : array {
 | 
			
		||||
        $accessKey = $this->minecraftAccessKey;
 | 
			
		||||
        $account = $accessKey->account;
 | 
			
		||||
 | 
			
		||||
        $result = [
 | 
			
		||||
            'accessToken' => $accessKey->access_token,
 | 
			
		||||
            'clientToken' => $accessKey->client_token,
 | 
			
		||||
            'selectedProfile' => [
 | 
			
		||||
                'id' => $account->uuid,
 | 
			
		||||
                'name' => $account->username,
 | 
			
		||||
                'legacy' => false,
 | 
			
		||||
            ],
 | 
			
		||||
        ];
 | 
			
		||||
 | 
			
		||||
        if ($includeAvailableProfiles) {
 | 
			
		||||
            // Сами моянги ещё ничего не придумали с этими availableProfiles
 | 
			
		||||
            $availableProfiles[0] = $result['selectedProfile'];
 | 
			
		||||
            $result['availableProfiles'] = $availableProfiles;
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return $result;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										74
									
								
								api/modules/authserver/models/AuthenticationForm.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										74
									
								
								api/modules/authserver/models/AuthenticationForm.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,74 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\modules\authserver\models;
 | 
			
		||||
 | 
			
		||||
use api\models\authentication\LoginForm;
 | 
			
		||||
use api\modules\authserver\exceptions\ForbiddenOperationException;
 | 
			
		||||
use api\modules\authserver\validators\RequiredValidator;
 | 
			
		||||
use common\models\MinecraftAccessKey;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
class AuthenticationForm extends Form {
 | 
			
		||||
 | 
			
		||||
    public $username;
 | 
			
		||||
    public $password;
 | 
			
		||||
    public $clientToken;
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [['username', 'password', 'clientToken'], RequiredValidator::class],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return AuthenticateData
 | 
			
		||||
     * @throws \api\modules\authserver\exceptions\AuthserverException
 | 
			
		||||
     */
 | 
			
		||||
    public function authenticate() {
 | 
			
		||||
        $this->validate();
 | 
			
		||||
 | 
			
		||||
        Yii::info("Trying to authenticate user by login = '{$this->username}'.", 'legacy-authentication');
 | 
			
		||||
 | 
			
		||||
        $loginForm = new LoginForm();
 | 
			
		||||
        $loginForm->login = $this->username;
 | 
			
		||||
        $loginForm->password = $this->password;
 | 
			
		||||
        if (!$loginForm->validate()) {
 | 
			
		||||
            $errors = $loginForm->getFirstErrors();
 | 
			
		||||
            if (isset($errors['login'])) {
 | 
			
		||||
                Yii::error("Cannot find user by login = '{$this->username}", 'legacy-authentication');
 | 
			
		||||
            } elseif (isset($errors['password'])) {
 | 
			
		||||
                Yii::error("User with login = '{$this->username}' passed wrong password.", 'legacy-authentication');
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // На старом сервере авторизации использовалось поле nickname, а не username, так что сохраняем эту логику
 | 
			
		||||
            $attribute = $loginForm->getLoginAttribute();
 | 
			
		||||
            if ($attribute === 'username') {
 | 
			
		||||
                $attribute = 'nickname';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            // TODO: если аккаунт заблокирован, то возвращалось сообщение return "This account has been suspended."
 | 
			
		||||
            // TODO: эта логика дублируется с логикой в SignoutForm
 | 
			
		||||
 | 
			
		||||
            throw new ForbiddenOperationException("Invalid credentials. Invalid {$attribute} or password.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $account = $loginForm->getAccount();
 | 
			
		||||
 | 
			
		||||
        /** @var MinecraftAccessKey|null $accessTokenModel */
 | 
			
		||||
        $accessTokenModel = MinecraftAccessKey::findOne(['client_token' => $this->clientToken]);
 | 
			
		||||
        if ($accessTokenModel === null) {
 | 
			
		||||
            $accessTokenModel = new MinecraftAccessKey();
 | 
			
		||||
            $accessTokenModel->client_token = $this->clientToken;
 | 
			
		||||
            $accessTokenModel->account_id = $account->id;
 | 
			
		||||
            $accessTokenModel->insert();
 | 
			
		||||
        } else {
 | 
			
		||||
            $accessTokenModel->refreshPrimaryKeyValue();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $dataModel = new AuthenticateData($accessTokenModel);
 | 
			
		||||
 | 
			
		||||
        Yii::info("User with id = {$account->id}, username = '{$account->username}' and email = '{$account->email}' successfully logged in.", 'legacy-authentication');
 | 
			
		||||
 | 
			
		||||
        return $dataModel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										23
									
								
								api/modules/authserver/models/Form.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										23
									
								
								api/modules/authserver/models/Form.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,23 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\modules\authserver\models;
 | 
			
		||||
 | 
			
		||||
use Yii;
 | 
			
		||||
use yii\base\Model;
 | 
			
		||||
 | 
			
		||||
abstract class Form extends Model {
 | 
			
		||||
 | 
			
		||||
    public function loadByGet() {
 | 
			
		||||
        return $this->load(Yii::$app->request->get());
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function loadByPost() {
 | 
			
		||||
        $data = Yii::$app->request->post();
 | 
			
		||||
        // TODO: проверить, парсит ли Yii2 raw body и что он делает, если там неспаршенный json
 | 
			
		||||
        /*if (empty($data)) {
 | 
			
		||||
            $data = $request->getJsonRawBody(true);
 | 
			
		||||
        }*/
 | 
			
		||||
 | 
			
		||||
        return $this->load($data);
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										37
									
								
								api/modules/authserver/models/InvalidateForm.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										37
									
								
								api/modules/authserver/models/InvalidateForm.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,37 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\modules\authserver\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\authserver\validators\RequiredValidator;
 | 
			
		||||
use common\models\MinecraftAccessKey;
 | 
			
		||||
 | 
			
		||||
class InvalidateForm extends Form {
 | 
			
		||||
 | 
			
		||||
    public $accessToken;
 | 
			
		||||
    public $clientToken;
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [['accessToken', 'clientToken'], RequiredValidator::class],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return bool
 | 
			
		||||
     * @throws \api\modules\authserver\exceptions\AuthserverException
 | 
			
		||||
     */
 | 
			
		||||
    public function invalidateToken() : bool {
 | 
			
		||||
        $this->validate();
 | 
			
		||||
 | 
			
		||||
        $token = MinecraftAccessKey::findOne([
 | 
			
		||||
            'access_token' => $this->accessToken,
 | 
			
		||||
            'client_token' => $this->clientToken,
 | 
			
		||||
        ]);
 | 
			
		||||
 | 
			
		||||
        if ($token !== null) {
 | 
			
		||||
            $token->delete();
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										45
									
								
								api/modules/authserver/models/RefreshTokenForm.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										45
									
								
								api/modules/authserver/models/RefreshTokenForm.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,45 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\modules\authserver\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\authserver\exceptions\ForbiddenOperationException;
 | 
			
		||||
use api\modules\authserver\validators\RequiredValidator;
 | 
			
		||||
use common\models\MinecraftAccessKey;
 | 
			
		||||
 | 
			
		||||
class RefreshTokenForm extends Form {
 | 
			
		||||
 | 
			
		||||
    public $accessToken;
 | 
			
		||||
    public $clientToken;
 | 
			
		||||
    public $selectedProfile;
 | 
			
		||||
    public $requestUser;
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [['accessToken', 'clientToken', 'selectedProfile', 'requestUser'], RequiredValidator::class],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    /**
 | 
			
		||||
     * @return AuthenticateData
 | 
			
		||||
     * @throws \api\modules\authserver\exceptions\AuthserverException
 | 
			
		||||
     */
 | 
			
		||||
    public function refresh() {
 | 
			
		||||
        $this->validate();
 | 
			
		||||
 | 
			
		||||
        /** @var MinecraftAccessKey|null $accessToken */
 | 
			
		||||
        $accessToken = MinecraftAccessKey::findOne([
 | 
			
		||||
            'access_token' => $this->accessToken,
 | 
			
		||||
            'client_token' => $this->clientToken,
 | 
			
		||||
        ]);
 | 
			
		||||
        if ($accessToken === null) {
 | 
			
		||||
            throw new ForbiddenOperationException('Invalid token.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $accessToken->refreshPrimaryKeyValue();
 | 
			
		||||
        $accessToken->update();
 | 
			
		||||
 | 
			
		||||
        $dataModel = new AuthenticateData($accessToken);
 | 
			
		||||
 | 
			
		||||
        return $dataModel;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										51
									
								
								api/modules/authserver/models/SignoutForm.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										51
									
								
								api/modules/authserver/models/SignoutForm.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,51 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\modules\authserver\models;
 | 
			
		||||
 | 
			
		||||
use api\models\authentication\LoginForm;
 | 
			
		||||
use api\modules\authserver\exceptions\ForbiddenOperationException;
 | 
			
		||||
use api\modules\authserver\validators\RequiredValidator;
 | 
			
		||||
use common\models\MinecraftAccessKey;
 | 
			
		||||
use Yii;
 | 
			
		||||
 | 
			
		||||
class SignoutForm extends Form {
 | 
			
		||||
 | 
			
		||||
    public $username;
 | 
			
		||||
    public $password;
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [['username', 'password'], RequiredValidator::class],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function signout() : bool {
 | 
			
		||||
        $this->validate();
 | 
			
		||||
 | 
			
		||||
        $loginForm = new LoginForm();
 | 
			
		||||
        $loginForm->login = $this->username;
 | 
			
		||||
        $loginForm->password = $this->password;
 | 
			
		||||
        if (!$loginForm->validate()) {
 | 
			
		||||
            // На старом сервере авторизации использовалось поле nickname, а не username, так что сохраняем эту логику
 | 
			
		||||
            $attribute = $loginForm->getLoginAttribute();
 | 
			
		||||
            if ($attribute === 'username') {
 | 
			
		||||
                $attribute = 'nickname';
 | 
			
		||||
            }
 | 
			
		||||
 | 
			
		||||
            throw new ForbiddenOperationException("Invalid credentials. Invalid {$attribute} or password.");
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        $account = $loginForm->getAccount();
 | 
			
		||||
 | 
			
		||||
        /** @noinspection SqlResolve */
 | 
			
		||||
        Yii::$app->db->createCommand('
 | 
			
		||||
            DELETE
 | 
			
		||||
              FROM ' . MinecraftAccessKey::tableName() . '
 | 
			
		||||
             WHERE account_id = :userId
 | 
			
		||||
        ', [
 | 
			
		||||
            'userId' => $account->id,
 | 
			
		||||
        ])->execute();
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
							
								
								
									
										35
									
								
								api/modules/authserver/models/ValidateForm.php
									
									
									
									
									
										Normal file
									
								
							
							
						
						
									
										35
									
								
								api/modules/authserver/models/ValidateForm.php
									
									
									
									
									
										Normal file
									
								
							@@ -0,0 +1,35 @@
 | 
			
		||||
<?php
 | 
			
		||||
namespace api\modules\authserver\models;
 | 
			
		||||
 | 
			
		||||
use api\modules\authserver\exceptions\ForbiddenOperationException;
 | 
			
		||||
use api\modules\authserver\validators\RequiredValidator;
 | 
			
		||||
use common\models\MinecraftAccessKey;
 | 
			
		||||
 | 
			
		||||
class ValidateForm extends Form {
 | 
			
		||||
 | 
			
		||||
    public $accessToken;
 | 
			
		||||
 | 
			
		||||
    public function rules() {
 | 
			
		||||
        return [
 | 
			
		||||
            [['accessToken'], RequiredValidator::class],
 | 
			
		||||
        ];
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
    public function validateToken() : bool {
 | 
			
		||||
        $this->validate();
 | 
			
		||||
 | 
			
		||||
        /** @var MinecraftAccessKey|null $result */
 | 
			
		||||
        $result = MinecraftAccessKey::findOne($this->accessToken);
 | 
			
		||||
        if ($result === null) {
 | 
			
		||||
            throw new ForbiddenOperationException('Invalid token.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        if (!$result->isActual()) {
 | 
			
		||||
            $result->delete();
 | 
			
		||||
            throw new ForbiddenOperationException('Token expired.');
 | 
			
		||||
        }
 | 
			
		||||
 | 
			
		||||
        return true;
 | 
			
		||||
    }
 | 
			
		||||
 | 
			
		||||
}
 | 
			
		||||
		Reference in New Issue
	
	Block a user