在Yii2的basic版本中默认是从一个数组验证用户名和密码,如何改为从数据表中查询验证呢?且数据库的密码要为哈希加密密码验证?
下面我们就一步一步解析Yii2的登录过程。
一. 创建user表模型表结构如下:
CREATE TABLE `user` ( `id` int(11) NOT NULL AUTO_INCREMENT, `pid` int(11) NOT NULL DEFAULT '0' COMMENT '父id', `username` char(70) NOT NULL COMMENT '用户名', `passWord` char(70) NOT NULL COMMENT '密码', `type` tinyint(4) NOT NULL DEFAULT '4' COMMENT '类型(1:总店,2:门店,3:管理员)', `created_time` int(11) NOT NULL COMMENT '注册时间', `updated_time` int(11) NOT NULL COMMENT '修改时间', `status` tinyint(4) NOT NULL DEFAULT '1' COMMENT '封禁状态,0禁止1正常', `login_ip` char(20) NOT NULL COMMENT '登录ip', `login_time` int(11) NOT NULL COMMENT '上一次登录时间', `login_count` int(10) NOT NULL DEFAULT '0' COMMENT '登陆次数', `update_password` int(10) NOT NULL DEFAULT '0' COMMENT '修改密码次数', PRIMARY KEY (`id`), KEY `pid` (`pid`), KEY `username` (`username`), KEY `type` (`type`), KEY `status` (`status`)) ENGINE=InnoDB DEFAULT CHARSET=utf8 COMMENT='登录管理表';
使用Gii创建user模型
将Yii2 basic之前user模型代码导入现在user中(先备份之前basic中的user模型)
1 namespace app\models; 2 3 use Yii; 4 5 /** 6 * This is the model class for table "user". 7 * 8 * @property integer $id 9 * @property integer $pid 10 * @property string $username 11 * @property string $password 12 * @property integer $type 13 * @property integer $created_time 14 * @property integer $updated_time 15 * @property integer $status 16 * @property string $login_ip 17 * @property integer $login_time 18 * @property integer $login_count 19 * @property integer $update_password 20 */ 21 class User extends \yii\db\ActiveRecord implements \yii\web\IdentityInterface 22 { public $authKey; 23 /*public $id; 24 public $username; 25 public $password; 26 public $authKey; 27 public $accessToken; 28 29 private static $users = [ 30 '100' => [ 31 'id' => '100', 32 'username' => 'admin', 33 'password' => 'admin', 34 'authKey' => 'test100key', 35 'accessToken' => '100-token', 36 ], 37 '101' => [ 38 'id' => '101', 39 'username' => 'demo', 40 'password' => 'demo', 41 'authKey' => 'test101key', 42 'accessToken' => '101-token', 43 ], 44 ]; 45 */ 46 47 /** 48 * @inheritdoc 49 */ 50 public static function tableName() 51 { 52 return 'user'; 53 } 54 55 /** 56 * @inheritdoc 57 */ 58 public function rules() 59 { 60 return [ 61 [['pid', 'type', 'created_time', 'updated_time', 'status', 'login_time', 'login_count', 'update_password'], 'integer'], 62 [['username', 'password', 'created_time', 'updated_time', 'login_ip', 'login_time'], 'required'], 63 [['username', 'password'], 'string', 'max' => 70], 64 [['login_ip'], 'string', 'max' => 20] 65 ]; 66 } 67 68 /** 69 * @inheritdoc 70 */ 71 public function attributeLabels() 72 { 73 return [ 74 'id' => 'ID', 75 'pid' => 'Pid', 76 'username' => 'Username', 77 'password' => 'Password', 78 'type' => 'Type', 79 'created_time' => 'Created Time', 80 'updated_time' => 'Updated Time', 81 'status' => 'Status', 82 'login_ip' => 'Login Ip', 83 'login_time' => 'Login Time', 84 'login_count' => 'Login Count', 85 'update_password' => 'Update Password', 86 ]; 87 } 88 89 /** 90 * @inheritdoc 91 */ 92 public static function findIdentity($id) 93 { 94 return static::findOne($id); 95 //return isset(self::$users[$id]) ? new static(self::$users[$id]) : null; 96 } 97 98 /** 99 * @inheritdoc100 */101 public static function findIdentityByAccessToken($token, $type = null)102 {103 return static::findOne(['access_token' => $token]);104 /*foreach (self::$users as $user) {105 if ($user['accessToken'] === $token) {106 return new static($user);107 }108 }109 110 return null;*/111 }112 113 /**114 * Finds user by username115 *116 * @param string $username117 * @return static|null118 */119 public static function findByUsername($username)120 {121 $user = User::find()122 ->where(['username' => $username])123 ->asArray()124 ->one();125 126 if($user){127 return new static($user);128 }129 130 return null;131 /*foreach (self::$users as $user) {132 if (strcasecmp($user['username'], $username) === 0) {133 return new static($user);134 }135 }136 137 return null;*/138 }139 140 /**141 * @inheritdoc142 */143 public function getId()144 {145 return $this->id;146 }147 148 /**149 * @inheritdoc150 */151 public function getAuthKey()152 {153 return $this->authKey;154 }155 156 /**157 * @inheritdoc158 */159 public function validateAuthKey($authKey)160 {161 return $this->authKey === $authKey;162 }163 164 /**165 * Validates password166 *167 * @param string $password password to validate168 * @return boolean if password provided is valid for current user169 */170 public function validatePassword($password)171 {172 return $this->password === $password;173 }174 }
之前的basic中User模型是继承了\yii\base\Object,为什么要继承这个类,那是因为
1 #在\yii\base\Object中,有构造方法 2 public function __construct($config = []) 3 { 4 if (!empty($config)) { 5 Yii::configure($this, $config); 6 } 7 $this->init(); 8 } 9 #继续追踪Yii::configure($this, $config)代码如下 10 public static function configure($object, $properties)11 {12 foreach ($properties as $name => $value) {13 $object->$name = $value;14 }15 16 return $object;17 }18 #正是因为有这两个方法,所以在User.php中19 public static function findByUsername($username)20 {21 foreach (self::$users as $user) {22 if (strcasecmp($user['username'], $username) === 0) {23 return new static($user);24 }25 }26 27 return null;28 }29 #将$user传递过来,通过static,返回一个User的实例。
当通过数据表查询时候没有必要再继承\yii\base\Object,因为不必为类似原来类变量赋值了。这个时候需要User模型继承\yii\db\ActiveRecord,因为要查询用。
findIdentity是根据传递的id返回对应的用户信息,getId返回用户id,getAuthKey和validateAuthKey是作用于登陆中的--记住我。这个authKey是唯一的,当再次登陆时,从cookie中获取authKey传递给validateAuthKey,验证通过,就登陆成功。
二. 模拟用户数据登录插入一条用户模拟数据
INSERT INTO `user` (`username`, `password`) VALUES ('admin', '123')
控制器Controller
1 /** 2 * 登录 3 */ 4 public function actionLogin() { 5 if (!\Yii::$app->user->isGuest) { 6 return $this->goHome(); 7 } 8 9 $model = new LoginForm(); 10 if ($model->load(Yii::$app->request->post()) && $model->login()) {11 12 13 $this->redirect(array('charisma/index'));14 } else {15 return $this->render('login', [16 'model' => $model,17 ]);18 }19 }
veiws中的login.php
1 <div class="well col-md-5 center login-box"> 2 <div class="alert alert-info"> 3 请填写您的用户名和密码 4 </div> 5 6 <?php $form = ActiveForm::begin([ 7 'id' => 'login-form', 8