如何在yii2中使用两个不同的模型或切换标识类进行登录?

Ins*_*ull 5 php yii yii2 yii2-user yii2-basic-app

我想允许用户从两个不同的模型登录.

config.php文件

'user' => [
        'identityClass' => 'app\models\User', //one more class here
        'enableAutoLogin' => false,
        'authTimeout' => 3600*2,
    ],
Run Code Online (Sandbox Code Playgroud)

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;
}
Run Code Online (Sandbox Code Playgroud)

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]);
 }
Run Code Online (Sandbox Code Playgroud)

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,
        ]);
}
Run Code Online (Sandbox Code Playgroud)

我不知道如何验证父登录.我试了几个小时找到解决方法,但没有成功.

我被困在Yii::$app->user->login($this->getUser(), $this->rememberMe ? 3600*24*30 : 0);因为用户表没有父登录记录.

我的问题

1)是否有可能有两个identityClass.如果是,那怎么样?
2)是否可以将ParentLogin模型扩展到User.如果是,那么如何验证?

参考

如何扩展用户类?

定义CiiUser类yii2中的自定义userIdentity类

Ton*_*ony 5

Joe Miller对于在用户表中使用一个用户类和一些布尔字段以检查用户的角色有很好的理解,作为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;
    }
}
Run Code Online (Sandbox Code Playgroud)

现在在控制器中:

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,
        ]);
}
Run Code Online (Sandbox Code Playgroud)

您的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]);
    }
}
Run Code Online (Sandbox Code Playgroud)

现在,当您登录时,您需要处理身份切换,因为在您拥有的配置中'identityClass' => 'app\models\User'.我们可以使用bootstrap属性:

//in your config file
'bootstrap' => [
    'log',
    //component for switching identities
    'app\components\IdentitySwitcher'
],
Run Code Online (Sandbox Code Playgroud)

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';
        }
    }
}
Run Code Online (Sandbox Code Playgroud)