• 面试官:设计一个异步并发限制吧


    上篇文章已经将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 实例对象) 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6
    • 7
    • 8
    • 9
    • 10
    • 11

    获取用户提交的数据

    解释:当路径为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 
    
    • 1
    • 2
    • 3
    • 4
    • 5

    每存在一个数据不符合规范,就会将它加入到error对象中。如果数据全部判断完成error对象仍然没有数据的话,那就说明数据全部校验成功,反之存在不合规的数据。

    调用validateCreateUser方法去验证:

     let {error,validate} = validateCreateUser(username,password,email);if(!validate){throw new HttpException(401,"用户数据验证失败",error)} 
    
    • 1

    如果为validate为true的话就说明error里没有数据,即校验成功,反之,失败。

    业务校验

    验证email是否已经存在

    去数据库中查询是否已经有email,有的话就不允许注册。

     const existUser = await User.findByPk(email) //所有数据库查询都为异步
    if(existUser){throw new HttpException(401,"用户邮箱已存在","email has exist")} 
    
    • 1
    • 2

    验证username是否唯一

    const existUsername = await User.findOne({username:username});if(existUsername){throw new HttpException(401,"用户名称已存在","username has exist")} 
    
    • 1

    在此之前已经通过了数据库校验数据的格式(主键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 
    
    • 1
    • 2
    • 3
    • 4
    • 5
    • 6

    所以数据库中创建的数据应为username,email,和加密后的密码。

    调用md5方法生成新的密文和存入数据库中:

     const md5PWD = await md5Password(password)
     const user = await User.create({username,password:md5PWD,email}) 
    
    • 1
    • 2

    创建进MySQL成功/失败

    成功则数据回显,失败则根据try catch捕捉错误数据

     if(user){res.json({data}) } } catch (error) { next(error)} 
    
    • 1

    至此完成用户注册的后台逻辑,从用户发送数据到后台,后台进行层层数据校验,校验无误的话将数据存储至数据库中。

    测试,模拟发送请求,查看数据库中是否成功User.create一条信息呢?

    确实存在,所以注册成功。


    拓展:真实开发中在传递数据时,用户信息不做处理会很容易被第三方拦截。。如图:

    other拦截之后就可以窃取你的账号密码,进行dy。

    方案一:对称加密

    服务端将私钥传递给客户端,于是两边同时进行加密,这样从客户端传递过来的就是密文,other拦截也不知道真实的信息是什么。但缺点:other可能会直接拦截密钥key,这样也会将传递的密文解开。 所以还是有一点点风险的。

    方案二:公钥加密

    公钥就是 服务端传递一个公钥给客户端,而能解开这个公钥的钥匙只存在服务端,这样唯一一把锁只在服务端,这样other即使拦截了公钥也解不开数据。这是最棒的方法了吧。

    由于我的项目过小,有这个优化想法,但未切入到本项目中应用,下次一定。

    最后

    整理了一套《前端大厂面试宝典》,包含了HTML、CSS、JavaScript、HTTP、TCP协议、浏览器、VUE、React、数据结构和算法,一共201道面试题,并对每个问题作出了回答和解析。

    有需要的小伙伴,可以点击文末卡片领取这份文档,无偿分享

    部分文档展示:



    文章篇幅有限,后面的内容就不一一展示了

    有需要的小伙伴,可以点下方卡片免费领取

  • 相关阅读:
    代码随想录算法训练营第五十一天 | 121. 买卖股票的最佳时机、122.买卖股票的最佳时机II
    Springboot集成SSE实现消息推送之单工通信
    Day10_Git版本控制、项目总结,preview_220627,
    C++ 跨平台UI框架 JUCE
    Flink CDC 2.0 主要是借鉴 DBLog 算法
    Python基于Flask的高校舆情分析,舆情监控可视化系统
    springboot集成spring-security(1)
    js调用android 方法
    [附源码]java毕业设计乡村振兴惠农推介系统
    「Verilog学习笔记」使用函数实现数据大小端转换
  • 原文地址:https://blog.csdn.net/pfourfire/article/details/127779205