天天看點

回顧yii2使用者注冊與登陸

前言:

很久沒用yii2寫登陸了。有些細節都有些忘了,寫一篇加深下印象,本次做的使用者登陸,使用的是yii2 user元件中的login方法來儲存使用者登陸狀态,這也是yii2比較優秀的地方,很多地方不用我們操心

目錄:

  1. 使用資料遷移,完成建表
  2. 完成注冊
  3. 完成登陸
  1. yii2中自帶了一個user表的資料遷移

資料遷移

我們在控制台目錄下找到它的位置

然後用指令行來執行資料遷移

image.png

當資料表建好了之後,我們需要在表中添加一個字段

資料表

就是最後的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方法來擷取

驗證方法

當驗證通過後,我們就可以對密碼進行加密了,我們使用加鹽加密。

  1. 首先我們需要生成随機的鹽值
$salt=Yii::$app->security->generateRandomString();
           

我們調用secrurity元件上的generateRandomString方法來生成一個32位的随機數

  1. 将使用者輸入的密碼和鹽值拼接,随後用security元件中的哈希方法進行加密
$this->password_hash=Yii::$app->security->generatePasswordHash($this->password_hash.$salt);
           

加密方式按個人喜好,也可使用md5加密

  1. 将生成的鹽值綁定到模型對象上
$this->salt=$salt;
           

鹽值需要儲存到資料庫中,用于使用者登陸時進行加密對比

  1. 儲存到資料庫中
if (!$this->save(false)) {
            throw new Exception($this->getErrors());
    }
           

由于其他資料在通過load方法綁定到模型上,我們将加密後的密碼和鹽值綁定上後,就可以儲存到資料庫中了

這裡有個小細節,當我們調用模型中的save方法儲存資料的時候,save方法還會調用validate來驗證資料,由于我的驗證規則中有驗證兩次輸入密碼必須一緻,當我們的密碼加密後,就和之前的重複密碼不一緻了,這樣就會導緻報錯。解決方法就是在save方法中傳入一個false,這樣就不會在save的同時進行驗證了

同樣的,登陸我們也是使用的ActiveForm和Bootstrap架構來寫表單,不同的是,我們登陸還加入了驗證碼 (驗證碼這次就不細談了)

  1. 前端頁面部分
<?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(); ?>
           
前面已經介紹過頁面,登陸頁面和注冊頁面類似。
  1. 控制器部分
首先是判斷驗證碼是否正确

驗證碼

綁定資料,驗證資料

驗證資料

調用模型方法,查找使用者,如果賬号密碼比對,調用user元件中的login方法完成登陸
在綁定資料驗證資料的時候,有個小細節,這時我們的業務隻需要驗證使用者名和密碼,并不需要驗證郵箱,可我們的驗證規則中寫了郵箱。或則在以後我們驗證規則中别的什麼字段的時候,我們可以采取部分驗證
//驗證部分資料(隻驗證使用者名,密碼,重複密碼)
        if (!$userModel->validate(['username','password_hash','repassword'])) {
            die('資料非法');
        }
           
将要驗證的字段以數組形式傳入validate就可以了,這樣就隻會驗證你傳入的字段的驗證規則.我稱之為部分驗證
  1. 模型部分
首先我們要使用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();
    }
           

前面的準備工作,搞定過後,我們就可以來完成登陸驗證

我們登陸分三部

  1. 擷取使用者輸入的使用者名,判斷是否有這個使用者
  2. 将鹽值從資料庫中取出,并于使用者輸入的密碼拼接
  3. 将加密後的使用者輸入的密碼,和資料庫中存儲的密碼進行比對

任意一步失敗,則抛出異常

第一部
$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登陸注冊的介紹了就寫到這裡了,如果有什麼地方不對,希望大神指正.謝謝

以上