我们在上一篇文章中写好了注册的接口,接下来打算完整地实现注册功能。
为了保存数据,我们需要一个数据库。对于小型的应用来说,其实使用sqlite3这样的轻量级数据库就可以了。但是为了让我们的技术栈更加贴近生产环境,我们这次使用MySQL来作为我们博客的数据库。
MySQL的安装与初始化
我们的服务器使用的是Debian,直接使用宝塔面板的软件商店就可以进行安装。在宝塔面板中也可以查看用户名和密码等事宜。
在node中连接到数据库
我们使用的是mysql包来进行MySQL和node的连接。我们先通过一个内部的server/createDatabase接口来创建一个数据表useraccount,包括一个用户名和密码,都是字符串varchar(length)类型。
const mysql = require('mysql')
const connection = mysql.createConnection({
host: 'localhost', // 数据库的地址,我们这里就是本地连接
user: 'root', // 用户名和密码,我们这里使用管理员用户
password: 'admin',
database: 'userdata' // 所连接的数据库名称,userdata数据库是之前在宝塔面板中创建好的
})
connection.connect();
app.get('/createDatabase',(req, res)=>{
connection.query(`create table useraccount
(
username varchar(20),
password varchar(512)
)`,
(err,res)=>{
console.log(err);
});
})
如何判断成功了?当你访问两次同样的路由你会发现会报错,因为数据表useraccount已经被创建完毕了。
密码加密
成功创建了数据库后我们就可以添加用户注册功能了,找到我们之前写的server/register路由,就可以接收到前端上传的用户名和密码了。
但是用户的密码直接通过明文存储在数据库中显然是不安全的,一定要通过一些手段进行加密。加密方式的演变这里不再阐述了,不了解的朋友可以参考粒粒姐的视频。我们这里要对后端存储的密码进行SHA512加密,这是一种目前安全性较高的加密方式。
加密使用的是crypto-js包,这个包支持很多的加密算法,包括MD5和我们今天要用的SHA512等。
const SHA512 = require('crypto-js/sha512');
app.post('/register',(req, res)=>{
const username = req.body.username;
let password = req.body.password;
password = SHA512(password).toString();
res.send(password);
})
使用Apifox添加一个快速请求,我们让其密码等于12345678,就能看到加密后的密文为fa585d89c851dd338a70dcf535aa2a92fee7836dd6aff1226583e88e0996293f16bc009c652826e0fc5c706695a03cddce372f139eff4d13959da6f1f5d3eabe,达到了加密的目的。
向数据库中插入数据
密码进行加密之后就可以放入数据库了。我们就再来学习一个SQL语句吧。insert into TABLE (param1, param2 ... paramn) values(?, ?, ... ?)代表着向TABLE表中写入这些参数,值会从values中顺序查找。
到了Node环境中,直接使用connection.query语句即可,注意query语句有三个参数,第一个参数是SQL语句,第二个参数是SQL语句的参数数组,最后一个参数便是回调函数(参数分别为err、res和field)。
app.post('/register',(req, res)=>{
const username = req.body.username;
let password = req.body.password;
password = SHA512(password).toString();
const addSql=`insert into useraccount (username, password) values(?,?)`;
connection.query(addSql,[username, password],(err)=>{
if(err){
res.send(`find err in inserting values, ${err}`);
}else{
res.send('insert successfully');
}
})
})
成功写入后,会看到insert successfully的提示。
数据的去重
我们存储的是用户的用户名和密码,因此用户名是不能重复的。但是我们可以发送两个同样的数据给后端,会发现不会报错。数据库里面存储了两条一模一样的数据,这是我们不能接受的。
应该如何优化呢?可以试着在数据插入的时候先筛选出和输入的用户名一样的数据,如果已经存在那么便会返回错误。这里就又学到了一个新的SQL语句select param1, param2, ... paramn from TABLE where CONDITION,代表从对应的数据表中选择对应的列。当没有查询到数据的时候,我们需要有一个标志让前端知道我们无法注册用户,这里可以让后端抛出状态码400,以及对应的错误信息。我们这里顺手把其他的错误判断也一并加入。
app.post('/register',(req, res)=>{
const username = req.body.username;
let password = req.body.password;
password = SHA512(password).toString();
const addSql=`insert into useraccount (username, password) values(?,?)`;
const selectSql = `select * from useraccount where username = '${username}'`;
connection.query(selectSql,(err,result)=>{
console.log(result);
if(result.length!==0){
res.status(400).send('用户名已存在');
}else{
connection.query(addSql,[username, password],(err)=>{
if(err){
res.status(500).send(`注册失败, ${err}`);
}else{
res.send('注册成功');
}
})
}
})
})
现在当你再用同样的用户名post两次后就会出现错误提示了。