代码之家  ›  专栏  ›  技术社区  ›  Insane Skull

如何在yii2中使用两个不同的模型或切换身份类登录?

  •  5
  • Insane Skull  · 技术社区  · 10 年前

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

    配置php

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

    登录表单.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;
    }
    

    用户.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]);
     }
    

    控制器.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 回复  |  直到 9 年前
        1
  •  5
  •   Tony    10 年前

    乔·米勒有一个很好的建议,在用户表中使用一个用户类和一些布尔字段来检查用户的角色,作为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';
            }
        }
    }
    
        2
  •  1
  •   Joe Miller    10 年前

    **编辑,这不起作用,您只能有一个身份类** **参考 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 模型,它将给出与原始模型相同的验证方法 用户 模型或实现 IdentityInterface 从零开始。从您的 parent 表,我建议使用第二种方法,因为列与 用户 表。

    然后你需要两个 loginForms : loginForm parentLoginForm ,因为每种情况下的验证都不同。

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