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

时间:2016-01-23 05:21:20

标签: php yii yii2 yii2-basic-app yii2-user

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

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。如果是,那么如何验证?

参考

How To extend user class?
Customising the CWebUser class
Custom userIdentity class in yii2

2 个答案:

答案 0 :(得分: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;
    }
}

现在在控制器中:

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';
        }
    }
}

答案 1 :(得分:1)

**编辑,这不起作用,你只能有一个身份类** **参考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表格不同。

您需要两个loginFormsloginFormparentLoginForm,因为每种情况下的验证都不同。

然后,在您的控制器中,您可以根据需要调用相应的登录表单。