05-blog-用户注册
上篇文章已经将json web token的加签和解签流程走完了,在业务场景中是当收到了用户登录的信息时jwt将登录信息通过key加密,和当用户再次发送请求时,去用key验证该请求携带的jwt是否正确无误。这两个场景做完了。
本次场景:注册用户。
注册用户是刚刚提到的所有场景的大前提,没有成功注册用户信息时,也不会进行用户登录,也不会再次发送请求,还没有token的事。总之,注册信息是大前提。
大致流程:
1. 获取用户提交的数据
2. 数据校验:是否为空/是否符合格式
3. 业务验证:是否唯一...
3.1 Email是否存在
3.2 username是否唯一
4. 创建用户:用户信息存储到数据库
4.1 密码加密:md5方式
4.2 user model 存储数据进入数据库
5. 结果返回
5.1 成功=>next()
5.2 失败=>next(HttpException 实例对象)
获取用户提交的数据
解释:当路径为http://localhost:3000/api/v1/users 的时候,将路由模块/api/v1/users/ 的请求方式设为post,并设置控制器。其中控制器就是用于注册用户时获取用户信息并进行一系列操作的器械。
先设置postman模拟客户端发送请求:
当点击send时,检查是否在req中的body携带了信息:
打印req.body:
成功接收到请求。第一步完成。
数据校验
校验用户提交的数据是否符合规范,即使用isEmpty()等方法判断。
数据可以成功过滤出的要求是:数据不能为空,且不为空的数据格式也要正确。如下:
const validator = require("validator")
// 用户注册---数据校验
const validateCreateUser = (username,password,email)=>{
let error={}
if(validator.isEmpty(username)){
error.username="username不能为空"
}
if(validator.isEmpty(password)){
error.password="password不能为空"
}
if(validator.isEmpty(email)){
error.email="email不能为空"
}
if(!validator.isEmpty(email)&&!validator.isEmail(email)){
error.email="email格式不对"
}
let validate = Object.keys(error).length<1 //true验证通过
return {error,validate}
}
module.exports = validateCreateUser
每存在一个数据不符合规范,就会将它加入到error对象中。如果数据全部判断完成error对象仍然没有数据的话,那就说明数据全部校验成功,反之存在不合规的数据。
调用validateCreateUser方法去验证:
let {error,validate} = validateCreateUser(username,password,email);
if(!validate){
throw new HttpException(401,"用户数据验证失败",error)
}
如果为validate为true的话就说明error里没有数据,即校验成功,反之,失败。
业务校验
验证email是否已经存在
去数据库中查询是否已经有email,有的话就不允许注册。
const existUser = await User.findByPk(email) //所有数据库查询都为异步
if(existUser){
throw new HttpException(401,"用户邮箱已存在","email has exist")
}
验证username是否唯一
const existUsername = await User.findOne({username:username});
if(existUsername){
throw new HttpException(401,"用户名称已存在","username has exist")
}
在此之前已经通过了数据库校验数据的格式(主键unique...),服务器也校验了数据的格式(是否为isEmpty),现在业务方面也要校验数据(人为规定),真是层层关卡。
如果这层通过的话,那就可以将数据传进数据库中了。
创建用户
md5加密password
在创建用户进数据库之前还需要将用户输入的密码进行不可逆的加密:md5;
npm install md5
安装
由于单纯md5加密容易被反推出来,所以一般都“加盐”,加盐之后如果反推出来也得不到真正的密码是什么。
const md5 = require("md5")
const SALT="salt" //盐
const md5Password = (password)=>{
return new Promise((resolve,reject)=>{
const md5PWD=md5(password+SALT) //加密后:原密码+盐
resolve(md5PWD)
})
}
module.exports=md5Password
所以数据库中创建的数据应为username,email,和加密后的密码。
调用md5方法生成新的密文和存入数据库中:
const md5PWD = await md5Password(password)
const user = await User.create({
username,
password:md5PWD,
email
})
创建进MySQL成功/失败
成功则数据回显,失败则根据try catch捕捉错误数据
if(user){
res.json({data})
}
} catch (error) {
next(error)
}
至此完成用户注册的后台逻辑,从用户发送数据到后台,后台进行层层数据校验,校验无误的话将数据存储至数据库中。
测试,模拟发送请求,查看数据库中是否成功User.create一条信息呢?
确实存在,所以注册成功。
拓展:真实开发中在传递数据时,用户信息不做处理会很容易被第三方拦截。。如图:
other拦截之后就可以窃取你的账号密码,进行dy。
方案一:对称加密
服务端将私钥传递给客户端,于是两边同时进行加密,这样从客户端传递过来的就是密文,other拦截也不知道真实的信息是什么。但缺点:other可能会直接拦截密钥key,这样也会将传递的密文解开。 所以还是有一点点风险的。
方案二:公钥加密
公钥就是 服务端传递一个公钥给客户端,而能解开这个公钥的钥匙只存在服务端,这样唯一一把锁只在服务端,这样other即使拦截了公钥也解不开数据。这是最棒的方法了吧。
由于我的项目过小,有这个优化想法,但未切入到本项目中应用,下次一定。
转载自:https://juejin.cn/post/7149758068593688583