简单练习前后端携带token验证(node后端篇)
简单的学了一下node.js,结合了网上的一些教程,简单的起了个后端的服务,用来练习前后端携带token验证。
1.连接mysql数据库
//mysql.js
const mysql = require('mysql')
const db = mysql.createPool({
host: 'localhost',
port: 3306,
user: 'root',
password: '123456',
database: 'demo',
})
module.exports = db
2.登陆注册路由模块user.js
//user.js
const express = require('express')
const router = express.Router()
// 导入登录注册路由处理函数对应的模块
const user_handler = require('../router_handler/userHandler')
// 1. 导入验证数据的中间件
const expressJoi = require('@escook/express-joi')
// 2. 导入需要的验证规则对象
const { reg_login_schema } = require('../schema/userSchema')
// 注册新用户,这里的expressJoi作为中间价函数,需要经过它才可以走注册路由处理函数,登录也是这样
router.post('/reguser', expressJoi(reg_login_schema), user_handler.regUser)
// 登录
router.post('/login', expressJoi(reg_login_schema), user_handler.login)
module.exports = router
2.1登录注册路由处理函数userHandler.js
// 导入数据库操作模块
const db = require('../db/mysql.js')
// 导入 bcryptjs 这个包,用于加密用户密码
const bcrypt = require('bcryptjs')
// 导入生成 Token 的包
const jwt = require('jsonwebtoken')
// 注册新用户的处理函数
exports.regUser = (req, res) => {
// 获取客户端提交到服务器的用户信息
const userinfo = req.body
// 定义 SQL 语句,查询用户名是否被占用
const sqlStr = 'select * from test2 where username=?'
db.query(sqlStr, userinfo.username, (err, results) => {
// 执行 SQL 语句失败
if (err) {
return res.cc(err)
}
// 判断用户名是否被占用,如果results长度大于0,就证明已经存在这个用户了
if (results.length > 0) {
return res.cc('用户名被占用,请更换其他用户名!')
}
// 调用 bcrypt.hashSync() 对密码进行加密
userinfo.password = bcrypt.hashSync(userinfo.password, 10)
// 定义插入新用户的 SQL 语句
const sql = 'insert into test2 set ?'
// 调用 db.query() 执行 SQL 语句
db.query(sql, { username: userinfo.username, password: userinfo.password }, (err, results) => {
// 判断 SQL 语句是否执行成功,如果失败
if (err) return res.cc(err)
// 注册用户成功
res.cc('注册成功!', 0)
})
})
}
// 登录的处理函数
exports.login = (req, res) => {
// 接收表单的数据
const userinfo = req.body
// 定义 SQL 语句
const sql = `select * from test2 where username=?`
// 执行 SQL 语句,根据用户名查询用户的信息
db.query(sql, userinfo.username, (err, results) => {
// 执行 SQL 语句失败
if (err) return res.cc(err)
// TODO:判断密码是否正确,正确为true,反之为flase
const compareResult = bcrypt.compareSync(userinfo.password, results.password)
if (!compareResult) return res.cc('登录失败!')
// TODO:在服务器端生成 Token 的字符串,password不能显示,要置为空
const user = { ...results, password: ''}
// 对用户的信息进行加密,生成 Token 字符串,第一个参数user是加密对象,第二个参数为加密密钥,第三个参数为有效时间
const tokenStr = jwt.sign(user, "mengli ^_^", { expiresIn: 1h })
// 调用 res.send() 将 Token 响应给客户端
res.send({
status: 0,
code:200,
message: '登录成功!',
token: 'Bearer ' + tokenStr,
})
})
}
2.2验证规则userSchema.js
// 导入定义验证规则的包
const joi = require('@hapi/joi')//新的验证规则的包改名为joi
// 定义用户名和密码的验证规则
const username = joi.string().alphanum().min(1).max(10).required()
const password = joi
.string()
.pattern(/^[\S]{6,12}$/)
.required()
3.其他信息路由模块news.js
//news.js
const express = require('express')
const router = express.Router()
//引入其他信息路由处理函数
const {getNews} = require('../router_handler/getNews')
router.post("/News",getNews)
module.exports = router
3.1其他信息路由处理函数
// 导入数据库操作模块
const db = require('../db/index')
// 获取相关信息的处理函数
exports.getNews = (req, res) => {
// 接收表单的数据
const {id} = req.body
console.log(id);
// 定义查询相关信息的 SQL 语句
const sql = `select news from text where id=?`
// 调用 db.query() 执行 SQL 语句
db.query(sql, id, (err, results) => {
// 执行 SQL 语句失败
if (err) return res.cc(err)
// 执行 SQL 语句成功,但是查询的结果可能为空
if (results.length !== 1) return res.cc('获取相关信息失败!')
// 相关信息获取成功
res.send({
status: 0,
message: '获取相关信息成功!',
data: results
})
})
}
4.主文件app.js
//app.js
// 导入 express
const express = require('express')
// 创建服务器的实例对象
const app = express()
const joi = require('@hapi/joi')//新的验证规则的包改名为joi
// 导入并配置 cors 中间件,用于解决跨域问题,允许跨域
const cors = require('cors')
app.use(cors())
//解析 application/x-www-form-urlencoded 格式的表单数据,前端也可以配置
app.use(express.urlencoded({ extended: false }))
//中间件处理函数
app.use((req, res, next) => {
// status 默认值为 1,表示失败的情况,不过status值0为成功的情况我也放在了这里
// err 的值,可能是一个错误对象,也可能是一个错误的描述字符串
res.cc = function (err, status = 1) {
res.send({
status,
message: err instanceof Error ? err.message : err,
})
}
//这里一定要next()
next()
})
// 一定要在路由之前配置解析 Token 的中间件
const expressJWT = require('express-jwt')
//这里的secret代表解密的密钥,unless是除了那个请求不需要经过解密,登录注册功能都不需要携带token,其他请求就需要携带token进行验证
app.use(expressJWT({ secret: "mengli ^_^" }).unless({ path: [/^/api/] }))
// 导入并使用登录注册路由模块
const userRouter = require('./router/user')
app.use('/api', userRouter)
// 导入并使用其他信息的路由模块
const News = require('./router/News')
app.use('/News', News)
// 定义错误级别的中间件
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)
//这里就不需要next(),因为已经是最后一步了
})
//端口为3007
app.listen(3007)
\