Я хочу разрешить вход пользователя из двух разных моделей.
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
, так как в каждом случае проверка различна.
Затем в вашем контроллере вы можете вызвать соответствующую форму входа в систему по мере необходимости.