持续创作,加速成长!这是我参与「掘金日新计划 · 6 月更文挑战」的第6天,点击查看活动详情
项目要求
通过一个小项目实践 Node.js 各个知识点。麻雀虽小,五脏俱全,这个项目会从 0~1,逐步完成所有需求。该项目实现接口有注册、登录、获取用户信息等等
登录注册
实现步骤
- 检测表单数据是否合法
- 根据用户名查询用户的数据
- 判断用户输入的密码是否正确
- 生成 JWT 的 Token 字符串
检测登录表单的数据是否合法
-
将
/router/user.js中,登录的路由代码修改如下// 用户登录 router.post('/login', expressJoi(reg_login_schema), userHandler.login)
根据用户名查询用户的数据
-
接收表单数据
const userInfo = req.body -
定义 SQL 语句
// 定义 SQL 语句 const sql = 'select * from ev_users where username=?' -
执行 SQL 语句,查询用户的数据
// 执行 SQL 语句,根据用户名查询用户的信息 db.query(sql, userInfo.username, (err, results) => { // 执行 SQL 语句失败 if(err) return res.cc(err) // 执行 SQL 语句成功,但是获取到的数据条数不等于1 if (results.length !== 1) return res.cc('登录失败!') // TODO: 判断密码是否正确 res.send('login ok') })
判断用户输入的密码是否正确
-
核心实现思路:调用
bcrypt.compareSync (用户提交的密码,数据库中的密码)方法比较密码是否一致。返回值是布尔值 (true 一致,false 不一致) -
代码实现:
// 使用用户输入的密码,和数据库中存储的密码进行对比 const compareResult = bcrypt.compareSync(userInfo.password, results[0].password) // 如果对比的结果是 false 则证明用户密码不对 if (!compareResult){ return res.cc('登录失败') }
生成 JWT 的 Token 字符串
核心注意点: 在生成 Token 字符串的时候,一定要先剔除密码和头像的值
-
通过 ES6 的高级语法,快速剔除 密码 和 头像 的值
const user = {...results[0], password: '', user_pic:''} /* user的值: { id: 7, username: 'admin6', password: '', nickname: null, email: null, user_pic: '' } */ -
运行如下命令,安装生成的 Token 字符串的包
npm install jsonwebtoken@8.5.1 -
在
/router_handler/user.js模块的头部区域,导入jsonwebtoken包// 导入生成 Token 的包 const jwt = require('jsonwebtoken') -
创建
config.js文件,并向外共享加密和还原 Token 的jwtsecreKey字符串const expressJoi = require("@escook/express-joi"); // 这是一个全局的配置文件 module.exports = { // 加密和解密 Token 的秘钥 jwtSecretKey: 'studyNode.', // Token 的有效期 expiresIn: '10h' } -
将用户信息对象加密成 Token 字符串
// 导入全局的配置文件 const config = require('../config') // 对用户信息进行加密,生成 Token 字符串 const tonkenStr = jwt.sign(user,config.jwtSecretKey, { expiresIn: config.expiresIn}) -
将生成的 Token 字符串响应给客户端
// 调用 res.send() 将 Token 响应给客户端 res.send({ status:0, message:'登录成功', token:'Bearer ' + tonkenStr })
配置解析 Token 的中间件
-
运行如下命令,安装解析 Token 的中间件
npm install express-jwt -
在
app.js中注册路由之前,配置解析 Token 的中间件// 解析 token的中间件 var { expressjwt: expJWT } = require("express-jwt") // 导入配置文件 const config = require('./config') // 使用 .unless({ path:[/^\/api\//] }) 指定哪些接口不需要进行 token 的身份验证 app.use( expJWT({ secret: config.jwtSecretKey, algorithms: ["HS256"], }).unless({ path:[/^\/api\//] }) ) -
在
app.js中的错误级别中间件,捕获并处理 Token 认证失败后的错误// 定义错误级别的中间件 app.use((err, req, res, next) => { // 验证失败导致的错误 if (err instanceof joi.ValidationError) return res.cc(err) // 身份认证失败的错误 if (err.name === 'UnauthorizedError') return res.cc('身份认证失败') // 未知的错误 res.cc(err) })