同福

做个用户管理系统(34)——使用绑定邮箱重置密码【20201223】

介绍

介绍

福哥今天带着大家完成TFUMS系统的忘记密码里面的第一种重置方式——通过绑定邮箱重置密码的前半部分功能的开发。

思路是这样的,我们先要知道哪个用户忘记了自己的密码,得到用户名之后判断用户名是否有绑定过邮箱。如果有绑定邮箱的话,我们就向这个绑定邮箱里发生一封邮件,邮件里面包含一个网址,网址携带一个验证码。如果用户可以接收到这封邮件,证明用户就是账号的所有者,可以让他重置密码。

模型user

forgotByEmail

public function forgotByEmail(int $userID){
        $myMail = new TFMail($this->tfphp);
        $myAES = new TFAES($this->tfphp);

        $userInfo = $this->getByTable("user", array($userID));
        if($userInfo == null){

            return 1;
        }

        $email = $userInfo['userEmail'];
        if($email == ""){

            return 2;
        }

        $SMTPArgs = TFConfig::get("SMTPArgs", "system");
        $subject = "重置你的TFUMS系统账号的登录密码";
        $linkData = serialize(array('action'=>"resetPassByBindEmail", 'id'=>$userID, 'timestamp'=>time()));
        $linkDataEncrypted = $myAES->encrypt($linkData, TFConfig::get("projectAESPK", "system"). date("YmdH0000"), "");
        $link = TFConfig::get("outUrl", "system"). "member/resetPassByEmail.htm?data=". $linkDataEncrypted;
        $body = "你好!<br/>
<br/>
请点击下面的链接完成密码重置操作!<br/><br/>
<a href=\"". $link. "\" target=\"_blank\">". $link. "</a><br/>
<br/>
TFUMS<br/>
". $SMTPArgs['email']. "<br/>";
        $myMail->setSMTP($SMTPArgs['host'], $SMTPArgs['port'], $SMTPArgs['user'], $SMTPArgs['pwd']);
        if(!$myMail->send($subject, $body, array(
            'from'=>$SMTPArgs['email'],
            'to'=>$email,
        ))){

            return 3;
        }

        return 0;
    }

接口控制器

doList

private function doList(){
    $user = new user($this->tfphp);
    $data = $this->tfphp->getRequest()->get->sn;

    // check data
    $userInfo = $user->forgotWay($data);
    if($userInfo == null){

        return null;
    }

    // get states
    $securityStates = $user->getSecurityStates($userInfo['userID']);

    // make new
    $newArr = array();
    if($securityStates['bindEmail']){
        $email = $userInfo['userEmail'];
        $emailArr = explode("@", $email);
        $szEmail = strlen($emailArr[0]);
        $newArr['email'] = str_repeat("*", $szEmail/2). substr($emailArr[0], $szEmail/2). "@". $emailArr[1];
    }

    return $this->tfphp->getResponse()->responseJSON(200, $newArr);
}

doSend

private function doSend(){
    $req = $this->tfphp->getRequest();
    $post = $req->post;
    $user = new user($this->tfphp);
    $data = $req->get->sn;

    try{
        // check data
        $userInfo = $user->forgotWay($data);
        if($userInfo == null){

            return $this->tfphp->getResponse()->responseJSON_CM(200, 1001095, "错误请求");
        }

        // forgot by email
        $ret = $user->forgotByEmail($userInfo['userID']);
        switch ($ret){
            case 1:
                return $this->tfphp->getResponse()->responseJSON_CM(200, 1001092, "用户名不存在");
                break;
            case 2:
                return $this->tfphp->getResponse()->responseJSON_CM(200, 1001093, "绑定邮箱无效");
                break;
            case 3:
                return $this->tfphp->getResponse()->responseJSON_CM(200, 1001094, "发送邮件失败");
                break;
        }
    }
    catch(\TypeError $e){

        return $this->tfphp->getResponse()->responseJSON_CM(200, 1001091, "错误请求");
    }

    // output
    return $this->tfphp->getResponse()->responseJSON_CM(200, 0, "OK");
}

视图模板

HTML代码

<!-- bind Email form begin -->
<div class="row login-form">
    <div class="col-sm-12">
        <h3 class="text-center">重置密码</h3>
        <p>系统将向您的绑定邮箱内发送一封邮件,通过邮件内的链接可以完成重置密码操作</p>
        <form>
            <div class="form-group">
                <label>电子邮箱</label>
                <span class="form-control" id="email"></span>
            </div>
            <div class="form-group">
                <button class="btn btn-primary btn-sm form-control">发送邮件</button>
            </div>
        </form>
    </div>
</div>
<!-- bind Email form end -->

JS代码

$.get("<% $TFReq->server->BASE_URI %>api/member/forgotByEmail/_list", {sn:"<% $TFReq->get->sn %>"}, function (d) {
    $('#email').html(d.email);
},"json");
// form
$('form').form({
    url: "<% $TFReq->server->BASE_URI %>api/member/forgotByEmail/_send?sn=<% $TFReq->get->sn %>",
    method: "post",
    validations: [

    ],
    onSuccess: function (d) {
        if(d.errcode == 0){
            document.location = '<% $TFReq->server->BASE_URI %>member/forgotByEmailOK.htm?sn=<% $TFReq->get->sn %>';
        }
        else{
            $('form').tips({
                text:d.errmsg
            });
        }
    },
    onError: function (d) {
        $('form').tips({
            text:"服务器响应错误"
        });
    },
    onValidationError: function (form, name, msg) {
        $('form').tips({
            text:msg
        });
        $('form').find('[name="'+ name +'"]').focus();
    }
});

讲解

模型user

forgotByEmail

首先检查用户是否存在,不存在就报错。

接着检查用户是否有绑定邮箱,没有绑定就报错。

然后使用AES加密一个数组获得验证码。

最后组织一封包含验证码发送给用户的绑定邮箱里面。

接口控制器

doList

获取用户的绑定邮箱地址,这里出于安全考虑对邮箱的用户名进行了部分屏蔽。

doSend

使用模型user的forgotByEmail方法发送重置密码的验证码邮件到用户的绑定邮箱里面。

视图模板

HTML代码

这里有一个使用span伪装的输入框,因为用户不需要输入邮箱地址,我们也不允许他改地址。

JS代码

首先通过list事件获取绑定邮箱地址,显示到span里面。

然后是一个标准表单处理程序,用来发送验证码邮件。

效果

发送验证码邮件的界面。

057fac45988a9907.jpg

验证码邮件内容。

6a79def9f024ba9b.jpg

总结

福哥今天带着童鞋们完成了TFUMS的使用绑定邮箱重置密码的前半部分功能的开发,这个功能再次用到了发送邮件的功能,利用发送带有验证码的邮件到用户邮箱里面的方式确定只有用户本人才能完成重置密码的操作,这样是比较安全的。

下一课,福哥将带着大家完成使用绑定邮箱重置密码的后半部分,敬请期待~