前言:
很久没用yii2写登录了。有些细节都有些忘了,写一篇加深下印象,本次做的用户登录,使用的是yii2 user组件中的login方法来保存用户登录状态,这也是yii2比较优秀的地方,很多地方不用我们操心
目录:
- 使用数据迁移,完成建表
- 完成注册
- 完成登录
- 使用数据迁移,完成建表
yii2中自带了一个user表的数据迁移
我们在控制台目录下找到它的位置
然后用命令行来执行数据迁移
当数据表建好了之后,我们需要在表中添加一个字段
就是最后的salt(盐值),字符形 32位,这个主要是用于密码加密,是目前比较流行的也是安全性比较高的加密方式
- 完成注册
注册页面我选择使用ActiveForm来做一个表单,需要使用ActiveForm就必须在渲染视图方法中给页面传递一个模型对象来配合使用
/**
* 渲染注册页面
*/
public function actionRegist()
{
$userModle = new User();
return $this->render('regist', ['usermodel' => $userModle]);
}
由于只是测试使用,并不是实际工作开发,这里注册就只做了账号密码和邮箱,并且没有涉及发邮件技术,如果对发邮件感兴趣的朋友可以点击看我另一篇博客yii2发邮件。这里就不多介绍了
页面我选用了bootstrap框架来做一个简单的表单
下面来看控制器部分
/**
* 完成注册
*/
public function actionRegistTodo()
{
//通过自己封装的私有方法来接收前台提交的表单数据
$formData = $this->_getRequest();
//创建模型对象
$userModel = new User();
//将数据绑定到模型对象中
if (!$userModel->load($formData)) {
exit('绑定数据错误');
}
try {
//调用模型中的创建用户的方法
if ($userModel->createUser()) {
echo '注册成功';
}
//捕获创建新用户方法中抛出的异常
} catch (Exception $exception) {
//打印异常的信息
var_dump($exception->getMessage());
}
}
控制器部分方法比较简洁,重点是控制器中调用的模型层的createUser方法
在创建用户之前,我们需要对前台传递过来的数据进行验证,我们知道程序员永远不能相信用户提交的数据,对于用户的提交,验证是必须的
由于我们的模型类继承了ActiveRecord
class User extends \yii\db\ActiveRecord
所以我们可以使用父类中的validate方法来验证表单数据
if (!$this->validate()) {
throw new Exception($this->getErrors());
}
当调用validate方法后,它会获取到们之前写好的rules方法里面的验证规则,如果数据符合验证规则,返回true,不符合返回false,并且会将不匹配的提示信息绑定到模型对象上,我们可以通过getErrors方法来获取
当验证通过后,我们就可以对密码进行加密了,我们使用加盐加密。
- 首先我们需要生成随机的盐值
$salt=Yii::$app->security->generateRandomString();
我们调用secrurity组件上的generateRandomString方法来生成一个32位的随机数
- 将用户输入的密码和盐值拼接,随后用security组件中的哈希方法进行加密
$this->password_hash=Yii::$app->security->generatePasswordHash($this->password_hash.$salt);
加密方式按个人喜好,也可使用md5加密
- 将生成的盐值绑定到模型对象上
$this->salt=$salt;
盐值需要保存到数据库中,用于用户登录时进行加密对比
- 保存到数据库中
if (!$this->save(false)) {
throw new Exception($this->getErrors());
}
由于其他数据在通过load方法绑定到模型上,我们将加密后的密码和盐值绑定上后,就可以保存到数据库中了
这里有个小细节,当我们调用模型中的save方法保存数据的时候,save方法还会调用validate来验证数据,由于我的验证规则中有验证两次输入密码必须一致,当我们的密码加密后,就和之前的重复密码不一致了,这样就会导致报错。解决方法就是在save方法中传入一个false,这样就不会在save的同时进行验证了
- 完成登录
同样的,登录我们也是使用的ActiveForm和Bootstrap框架来写表单,不同的是,我们登录还加入了验证码 (验证码这次就不细谈了)
- 前端页面部分
<?php $form = \yii\bootstrap\ActiveForm::begin(['action' => \yii\helpers\Url::to(['login/login-check'])]) ?>
<table>
<tr>
<!-- 用户名-->
<?= $form->field($model, 'username') ?>
</tr>
<tr>
<!-- 密码-->
<?= $form->field($model, 'password_hash') ?>
</tr>
<tr>
<!-- 重复密码-->
<?= $form->field($model, 'repassword') ?>
</tr>
<tr>
<!-- 验证码图片-->
<td><img style="cursor:pointer;" id="captchaImg" src="<?= \yii\helpers\Url::to(['login/captcha']) ?>" alt=""></td>
</tr>
<tr>
<td>
<label for="captcha">验证码</label>
<!-- 验证码输入框-->
<input type="text" name="captcha" class="input-xxlarge">
</td>
</tr>
<tr>
<td><input type="submit" value="提交" class="btn btn-success"></td>
<td><a class="btn btn-warning" href="<?=\yii\helpers\Url::to(['login/regist'])?>">注册</a></td>
</tr>
</table>
<?php $form::end(); ?>
前面已经介绍过页面,登录页面和注册页面类似。
- 控制器部分
首先是判断验证码是否正确
绑定数据,验证数据
调用模型方法,查找用户,如果账号密码匹配,调用user组件中的login方法完成登录
在绑定数据验证数据的时候,有个小细节,这时我们的业务只需要验证用户名和密码,并不需要验证邮箱,可我们的验证规则中写了邮箱。或则在以后我们验证规则中别的什么字段的时候,我们可以采取部分验证
//验证部分数据(只验证用户名,密码,重复密码)
if (!$userModel->validate(['username','password_hash','repassword'])) {
die('数据非法');
}
将要验证的字段以数组形式传入validate就可以了,这样就只会验证你传入的字段的验证规则.我称之为部分验证
- 模型部分
首先我们要使用yii2自带的login方法来保存登录状态,我们需要我们的user模型继承IdentityInterface身份验证接口,并且实现它里面的抽象方法
下面是实现接口的代码
/**
* 通过传递的id,返回查到的数据模型对象的静态方法
* @param int|string $id
* @return static
*/
public static function findIdentity($id)
{
return User::findOne($id);
}
/**
* 通过传递token,返回查到的数据模型对象的静态方法
* @param mixed $token
* @param null $type
* @return static
*/
public static function findIdentityByAccessToken($token, $type = null)
{
return User::findOne(['password_reset_token'=>$token]);
}
/**
* 返回当前对象的id
* @return string
*/
public function getId()
{
return $this->id;
}
/**
* 获取当前对象的auth_key
* @return mixed
*/
public function getAuthKey()
{
return $this->auth_key;
}
/**
*对比传递过来的authkey于当前对象的auth_key
* @param string $authKey
* @return bool
* 返回对比结果
*/
public function validateAuthKey($authKey)
{
return $authKey===$this->getAuthKey();
}
前面的准备工作,搞定过后,我们就可以来完成登录验证
我们登录分三部
- 获取用户输入的用户名,判断是否有这个用户
- 将盐值从数据库中取出,并于用户输入的密码拼接
- 将加密后的用户输入的密码,和数据库中存储的密码进行比对
任意一步失败,则抛出异常
第一部
$username=$this->username;
$password_hash=$this->password_hash;
//查询数据表中用户名
$userModel=User::findOne(['username'=>$username]);
if (empty($userModel)) {
throw new Exception('用户或密码错误');
}
第二部
//账号存在,对比密码
$salt=$userModel->salt;
//用户表单提交的密码加密
$securityPassword=$password_hash.$salt;
拼接后的密码不需要进行hash加密,我们使用yii2 security组件中的validatePassword的方法来比对
第三部
if (!Yii::$app->security->validatePassword($securityPassword,$userModel->password_hash)) {
throw new Exception('用户或密码错误');
}
return $userModel;
密码验证通过后,则返回查找到的数据模型对象
控制器获取到了数据模型对象后就可以调用user组件中的login方法,进行保存用户登录的状态了
好了,本次回顾yii2登录注册的介绍了就写到这里了,如果有什么地方不对,希望大神指正.谢谢
以上