Как войти в систему с использованием двух разных моделей или класса идентификации коммутатора в yii2?

Я хочу разрешить вход пользователя из двух разных моделей.

config.php

'user' => [ 'identityClass' => 'app\models\User', //one more class here 'enableAutoLogin' => false, 'authTimeout' => 3600*2, ], 

LoginForm.php

  public function rules() { return [ // username and password are both required [['username', 'password'], 'required'], // rememberMe must be a boolean value ['rememberMe', 'boolean'], // password is validated by validatePassword() ['password', 'validatePassword'], ]; } public function validatePassword($attribute, $params) { if (!$this->hasErrors()) { $user = $this->getUser(); if (!$user || !$user->validatePassword($this->password)) { $this->addError($attribute, Yii::t('user', 'Incorrect username or password.')); } } } public function login() { if ($this->validate()) { return Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0); } else { return false; } } public function parentLogin() { // How to validate parent Login? } public function getUser() { if ($this->_user === false) { $this->_user = User::findByUsername($this->username); } return $this->_user; } 

User.php

 class User extends \yii\db\ActiveRecord implements IdentityInterface { public static function tableName() { return 'users'; } public static function findIdentity($id) { return static::findOne($id); } public static function findByUsername($username) { return static::findOne(['user_login_id' => $username]); } 

controller.php

  public function actionLogin() { // Working } public function actionParentLogin() { $model = new LoginForm(); if ($model->load(Yii::$app->request->post()) && $model->parentLogin()) { $parent = ParentLogin::find()->where(['p_username' => $model->p_username])->one(); if($parent){ \Yii::$app->session->set('p_id',$parent->p_id); return $this->redirect(['parent-dashboard']); } else { Yii::$app->getSession()->setFlash('error', Yii::t('site', 'Incorrect username or password.')); } } return $this->render('parent-login', [ 'model' => $model, ]); } ,  public function actionLogin() { // Working } public function actionParentLogin() { $model = new LoginForm(); if ($model->load(Yii::$app->request->post()) && $model->parentLogin()) { $parent = ParentLogin::find()->where(['p_username' => $model->p_username])->one(); if($parent){ \Yii::$app->session->set('p_id',$parent->p_id); return $this->redirect(['parent-dashboard']); } else { Yii::$app->getSession()->setFlash('error', Yii::t('site', 'Incorrect username or password.')); } } return $this->render('parent-login', [ 'model' => $model, ]); } 

Я не знаю, как проверить регистрацию родителя. Я много часов пытался найти обходной путь, но не смог.

Я застрял в Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0); потому что в таблице пользователя нет родительских записей входа.

Мои вопросы

1) Возможно ли иметь два identityClass . Если да, то как?
2) Можно ли расширить модель ParentLogin для User . Если да, то как проверить?

Рекомендации

Как расширить класс пользователя?
Настройка класса CWebUser
Пользовательский класс userIdentity в yii2

    Джо Миллер очень хорошо разбирается в том, что один пользовательский класс и некоторые логические поля в таблице пользователей проверяют роль пользователя в качестве альтернативы rbac. Но поскольку в вашей ситуации это невозможно, вот что я могу вам предложить (этот подход проверен на полпути и должен быть принят).

    Да, вы можете иметь два или более идентификационных класса, но не в одно и то же время. Вам нужно обработать переключение между идентификаторами. LoginForm первых, я предлагаю вам немного изменить вашу модель LoginForm :

     class LoginForm extends Model { public $username; public $password; public $rememberMe = true; // we added this parameter to handle userModel class // that is responsible for getting correct user public $userModel; private $_user = false; /* all other methods stay same */ /** * Finds user by [[username]] * * @return User|null */ public function getUser() { if ($this->_user === false) { // calling findByUsername method dynamically $this->_user = call_user_func( [$this->userModel, 'findByUsername'], $this->username ); } return $this->_user; } } 

    Теперь в контроллере:

     public function actionParentLogin() { $model = new LoginForm(['userModel' => ParentLogin::className()]); // calling model->login() here as we usually do if ($model->load(Yii::$app->request->post()) && $model->login()) { // no need to worry about checking if we found parent it's all done polymorphycally for us in LoginForm // here is the trick, since we loggin in via parentLogin action we set this session variable. Yii::$app->session->set('isParent', true); return $this->redirect(['parent-dashboard']); } else { Yii::$app->getSession()->setFlash('error', Yii::t('site', 'Incorrect username or password.')); } } return $this->render('parent-login', [ 'model' => $model, ]); } 

    Ваша модель parentLogin должна parentLogin модель User чтобы все это работало:

     class parentLogin extends User { public static function tableName() { //you parent users table name return 'parent_users'; } public static function findByUsername($username) { return static::findOne(['p_username' => $username]); } } 

    Теперь, когда вы вошли в систему, вам необходимо обработать идентификатор, потому что в конфигурации у вас есть 'identityClass' => 'app\models\User' . Для этого мы можем использовать свойство bootstrap :

     //in your config file 'bootstrap' => [ 'log', //component for switching identities 'app\components\IdentitySwitcher' ], 

    Класс IdentitySwitcher:

     class IdentitySwitcher extends Component implements BootstrapInterface { public function bootstrap($app) { //we set this in parentLogin action //so if we loggin in as a parent user it will be true if ($app->session->get('isParent')) { $app->user->identityClass = 'app\models\ParentLogin'; } } } 

    ** Редактировать, это не сработает, у вас может быть только один класс идентификации ** ** Ref https://github.com/yiisoft/yii2/issues/5134 ** Я бы предложил попробовать следующее – не проверено.

    В вашей конфигурации добавьте дополнительный интерфейс идентификации, как вы предлагаете;

     'user' => [ 'identityClass' => 'app\models\User', 'enableAutoLogin' => false, 'authTimeout' => 3600*2, ], 'parent' => [ 'identityClass' => 'app\models\Parent', 'enableAutoLogin' => false, 'authTimeout' => 3600*2, ], 

    Затем ваша модель Parent может расширить модель User , которая даст те же методы проверки, что и исходная модель User , или реализует IdentityInterface с нуля. Из ваших имен столбцов в parent таблице я предлагаю второй метод, так как столбцы отличаются от таблицы User .

    Тогда вам понадобится два loginForms : loginForm и parentLoginForm , так как в каждом случае проверка различна.

    Затем в вашем контроллере вы можете вызвать соответствующую форму входа в систему по мере необходимости.