Vue博客搭建(14)验证码

1,044 阅读4分钟

在之前的文章中,我们实现了简易的注册系统。但是在主流的生产环境中很少会使用用户名登录,因此我们要对注册系统进行完善,注册时必须使用邮箱和验证邮件,并且每次登录和注册时都需要输入验证码。为了便于接下来的使用,还可以给在数据库中添加用户的头像、用户生日和个人简介等信息空位。

数据库的扩充

之前的数据库中只有用户名和密码两个键,我们需要在原来的数据库的基础上添加一个主键,就是用户的邮箱。

MySQL扩充数据库的指令为alter table TABLE add COLUMN TYPE。后端的接口统一为/edit。但是因为我们在之前创建的表中没有主键,因此主键为空,我们不能重新创建一个新的主键,否则会报错。因此这里的方案是删除原先的数据表,创建一个新的(在生产环境中千万不要这么做!)。SQL删除数据表的语句为drop table TABLENAME

对后端的注册接口也应该有相应的调整:

app.post('/register',(req, res)=>{
    const email = req.body.email;
    const username = req.body.username;
    let password = req.body.password;
    password = SHA512(password).toString();
    const addSql=`insert into useraccount (email, username, password) values(?,?,?)`;
    const selectSql = `select * from useraccount where email = '${email}' or username = '${username}'`;
    connection.query(selectSql,(err,result)=>{
        if(result.length!==0){
            res.status(400).send('邮箱或用户名已被占用');
        }else{
            connection.query(addSql,[email, username, password],(err)=>{
            if(err){
                res.status(500).send(`注册失败, ${err}`);
            }else{
                res.send('注册成功');
            }
    })
        }
    })
})

这样的话当邮箱或用户名已被占用时便会产生提示,注意“或”条件在SQL语句中的写法。

但是在实际的生产环境中,网站的用户名可以重复(例如小红书)也可以不重复(例如b站),本网站采取了用户名可以重复的规则,因此上面的代码并不适用,需要稍作修改,这里就不再给出了。而后端代码要注意,我们上传时的author全部改为了作者的电子邮箱,邮箱名称不能对外暴露,因此后端发回文章数据时需要把对应的author字段改为用户名。

app.get('/getArticle/:id',(req, res)=>{
    const id = req.params.id;
    const selectSql = `select * from articles where id = '${id}'`;
    connection.query(selectSql, (err, result)=>{
        if(result.length === 0){
            res.status(404).end();
        }else{
            const article = result[0];
            const email = article.author;
            const changeUsernameSql = `select username from useraccount where email='${email}'`;
            connection.query(changeUsernameSql,(err,username)=>{
                article.author = username[0].username;
                res.send(article);
            })
        }
    })
})

相应的,/login只能使用邮箱登录,对应的前端代码也需要修改,这里也不再给出了。

注册时的验证与验证码

现在我们直接就能注册,不能验证是否为脚本批量自动注册,因此我们需要一个图形验证码来进行识别。

图形验证码的大致流程如下:后端根据参数生成一个图片文件发送给前端,前端按下注册按钮后,输入的验证码会连同其他数据一起被发送到前端进行校验,首先校验验证码,如果验证码错误会直接返回。

先看后端生成验证码的代码,还是需要一个接口/getCaptcha,对应的包使用的是svg-captcha,同时还需要express-session包来存储session,因为值需要在服务器中存储以供校验。

const session = require('express-session');

app.use(session({ 
    secret: 'keyboard cat', 
    // session秘钥,用来将其注册到cookie中
}))

app.get('/getCaptcha',(req, res)=>{
    const captcha = svgCaptcha.create({
        size: 6,
        ignoreChars: 'oi10',
        noise: 3,
        color: true,
    });
    req.session.captcha = captcha.text;
    // 把验证码的文本保存到session中,因为文本需要服务器来保存(需要express-session)
    res.type('svg');
    res.send(captcha.data);
    // 把svg格式的验证码发送到客户端中。
})

对应的前端代码如下。注意到我们这里使用的是v-html,这是因为传回去的数据是一个<span>标签,为了其能够被html来渲染,我们需要使用v-html指令。

<script setup>
function getCaptcha(){
    axios.get('/server/getCaptcha')
    .then((response)=>{
        captcha.value = response.data;
    })
}

getCaptcha();
// 在最开始需要获取一个验证码

</script>

<template>
    <div class="informationInput">
        <h1>注册</h1>
        <h2>邮箱</h2>
        <input v-model="emailInput"/>
        <h2>用户名</h2>
        <input v-model="usernameInput"/>
        <h2>密码</h2>
        <input v-model="passwordInput"/>
        <h2>验证码</h2>
        <input v-model="captchaInput"/>
        <div v-html="captcha" @click="getCaptcha"></div>
        <button @click="register">注册</button>
    </div>
</template>

同理,我们需要给/login页面也加上验证码的验证。这里就不再重复给出代码了。

node应用中的多文件耦合

在上面的代码中,/login/register方法体中都有一个验证码是否正确的判断,我们在两段代码中使用了相同的代码片段,因此我们可以进行封装。封装是一定不可能被放在相同的文件中,因此我们可以在根目录中单独创建一个functions/checkCaptcha.js文件。

function checkCaptcha(input, realValue){
    return input.toLowerCase() === realValue.toLowerCase();
}

module.exports=checkCaptcha;

module.exprts是模块的导出属性,是一个对象,可以有很多的属性。在这个文件中只有一个函数,因此在index.js中的函数也就是你require语句的返回值。如果你不知道应该怎么样使用对应的模块,就看对应的module.exports即可。

因此在index.js中需要这样引用:

const checkCaptcha = require('./funcitons/checkCaptcha')

if(!checkCaptcha(captcha, req.session.captcha)){
        req.session.captcha ='';
        res.status(400).send('验证码错误');
        return;
}

这样代码的重复度就降低了很多。