如何在 yii2 中使用两个不同的模型登录或切换身份 class?
How to login using two different model or switch identity class in 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);
因为用户 table 没有父登录记录。
我的问题
1) 是否可以有两个identityClass
。如果是那么如何?
2) 是否可以将 ParentLogin
模型扩展到 User
。如果是那么如何验证?
参考资料
How To extend user class?
Customising the CWebUser class
Custom userIdentity class in yii2
** 编辑,这个不行,你只能有一个身份class **
** 参考 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
table 中的列名称,我建议使用第二种方法,因为列与 User
table.
不同
然后您将需要两个 loginForms
:loginForm
和 parentLoginForm
,因为每种情况下的验证都不同。
然后,在您的控制器中,您可以根据需要调用相应的登录表单。
Joe Miller 有一个很好的建议,即让一个用户 class 和用户 table 中的一些布尔字段来检查用户的角色,作为 rbac 的替代方案。但由于在您的情况下这是不可能的,因此我可以向您提供以下建议(此方法已经过 half-way 测试,需要采用)。
是的,您可以拥有两个或更多身份类别,但不能同时拥有。您需要处理身份之间的切换。所以首先,我建议您稍微编辑一下 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:
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';
}
}
}
我想允许用户从两个不同的模型登录。
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);
因为用户 table 没有父登录记录。
我的问题
1) 是否可以有两个identityClass
。如果是那么如何?
2) 是否可以将 ParentLogin
模型扩展到 User
。如果是那么如何验证?
参考资料
How To extend user class?
Customising the CWebUser class
Custom userIdentity class in yii2
** 编辑,这个不行,你只能有一个身份class ** ** 参考 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
table 中的列名称,我建议使用第二种方法,因为列与 User
table.
然后您将需要两个 loginForms
:loginForm
和 parentLoginForm
,因为每种情况下的验证都不同。
然后,在您的控制器中,您可以根据需要调用相应的登录表单。
Joe Miller 有一个很好的建议,即让一个用户 class 和用户 table 中的一些布尔字段来检查用户的角色,作为 rbac 的替代方案。但由于在您的情况下这是不可能的,因此我可以向您提供以下建议(此方法已经过 half-way 测试,需要采用)。
是的,您可以拥有两个或更多身份类别,但不能同时拥有。您需要处理身份之间的切换。所以首先,我建议您稍微编辑一下 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:
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';
}
}
}