Как войти, используя две разные модели или переключить класс идентичности в 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,
]);
}
Я не знаю, как проверить родительский логин. Я часами пытался найти обходной путь, но безуспешно.
Я застрял на Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);
потому что у таблицы пользователя нет родительских записей входа.
Мои вопросы
1) можно ли иметь два identityClass
, Если да, то как?
2) Можно ли продлить ParentLogin
модель для User
, Если да, то как проверить?
Рекомендации
Как продлить класс пользователя?
Настройка класса CWebUser
Пользовательский класс userIdentity в yii2
2 ответа
У Джо Миллера есть хорошее предположение о наличии одного пользовательского класса и нескольких логических полей в таблице пользователей для проверки роли пользователя, в качестве альтернативы rbac. Но поскольку в вашей ситуации это невозможно, вот что я могу вам предложить (этот подход проверен наполовину и его необходимо принять).
Да, вы можете иметь два или более identityClasses, но не одновременно. Вы должны справиться с переключением между личностями. Итак, во-первых, я предлагаю вам отредактировать 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
модель должна расширяться 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';
}
}
}
** Изменить, это не работает, вы можете иметь только один класс идентификации ** ** Ссылка 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
, так как валидация отличается в каждом случае.
Затем, в вашем контроллере, вы можете вызвать соответствующую форму входа в систему, как требуется.