首先做一下声明,本篇博客来源于BiliBili上全栈之巅主播Johnny的视频[1小时搞定NodeJs(Express)的用户注册、登录和授权(https://www.bilibili.com/video/av49391383),对其进行了整理。自己跟着视频做,感觉收获不少。 最近在学些NodeJs和Express框架开发后台接口,Express 是一个保持最小规模的灵活的 Node.js Web 应用程序开发框架,为 Web 和移动应用程序提供一组强大的功能。看到B站上全栈之巅-Node.js+Vue.js全栈开发深度爱好者和实践者,感觉Johnny博主的系列视频讲解得不错,其中看到一个视频是1小时搞定NodeJs(Express)的用户注册、登录和授权,介绍了在Express中怎么做用户登录和注册,以及jsonwebtoken的验证,需要在系统中安装MongoDB数据库;于是在自己的Windows10系统下使用VSCode跟着做,前提是要安装好NodeJs和Express开发环境,以及在Windows系统中配置好MongoDB数据库,关于在Windows下安装MongoDB可以参考菜鸟教程中的Windows 平台安装 MongoDB和windows环境下启动mongodb服务。
我的nodejs版本是:v10.16.0, npm版本是:6.9.0,cnpm的版本是6.1.0,express的版本是4.16.1,由于npm在国内安装比较慢,最好用淘宝的cnpm镜像安装。 如下图所示:
使用到的第三方库有:express、jsonwebtoken、bcryptjs、mongoose;nodemon用于调试
cnpm install express@next
cnpm install -g nodemon
cnpm install jsonwebtoken
cnpm install bcryptjs
cnpm install mongoose
另外,还需要在VSCode中安装扩展的rest-client插件,它是用于在VSCode中发起http请求的一个插件,可以通过代码的方式发起http请求,包括get、post、put去请求。类似于Postman,Postman是一款功能强大的网页调试与发送网页HTTP请求的Chrome插件。其中Rest-Client插件在VSCode中如下图所示:
创建一个EXPRESS-AUTH的文件夹,在VSCode中打开此文件夹,然后使用如下命令安装好依赖库
cnpm install express@next
cnpm install -g nodemon
cnpm install jsonwebtoken
cnpm install bcryptjs
cnpm install mongoose
然后分别在EXPRESS-AUTH文件夹下创建test.http、server.js、model.js,分别表示发起http请求的文件,服务接口文件、MongoDB Model接口文件
/* jshint esversion: 8 */
// const mongoose = require('mongoose')
const { User } = require('./models')
const express = require('express')
const jwt = require('jsonwebtoken')
const app = express();
app.use(express.json())
const SECRET = "fdfhfjdfdjfdjerwrereresaassa2dd@ddds"
// app.get('/', async(req, res) => {
// res.send('ok')
// })
app.get('/api', (req, res) => res.send('Hello World!'))
// 从MongoDB数据库express-auth中的User表查询所有的用户信息
app.get('/api/users', async(req, res) => {
const users = await User.find()
res.send(users)
})
app.post('/api/register', async (req, res) => {
// console.log(req.body)
// 在MongoDB数据库表USer中新增一个用户
const user = await User.create({
username: req.body.username,
password: req.body.password,
})
// res.send('register')
res.send(user)
})
app.post('/api/login', async (req, res) => {
// res.send('login')
// 1.看用户是否存在
const user = await User.findOne({
username: req.body.username
})
if (!user) {
return res.status(422).send({
message: '用户名不存在'
})
}
// 2.用户如果存在,则看密码是否正确
const isPasswordValid = require('bcryptjs').compareSync(
req.body.password,
user.password
)
if(!isPasswordValid) {
// 密码无效
return res.status(422).send({
message: '密码无效'
})
}
// 生成token
const token = jwt.sign({
id: String(user._id),
}, SECRET)
res.send({
user,
token
})
})
// 中间件:验证授权
const auth = async (req, res, next) => {
// 获取客户端请求头的token
const rawToken = String(req.headers.authorization).split(' ').pop()
const tokenData = jwt.verify(rawToken, SECRET)
// console.log(tokenData)
// 获取用户id
const id = tokenData.id;
// const user = await User.findById(id)
req.user = await User.findById(id)
next()
}
app.get('/api/profile', auth, async (req, res) => {
res.send(req.user)
})
app.listen(3001, () => {
console.log('http://localhost:3001')
})
/* jshint esversion: 8 */
const mongoose = require('mongoose')
// const bcrypt = require('bcrypt')
// const saltRounds = 10
// const bcrypt = require('bcryptjs')
mongoose.connect('mongodb://localhost:27017/express-auth', {
useNewUrlParser:true,
useUnifiedTopology: true,
useCreateIndex: true
})
const bcrypt = require('bcryptjs')
// 定义一个用户模型,username是唯一的索引,表示不能被重复
const UserSchema = new mongoose.Schema({
username: { type: String, unique: true },
password: {
type: String,
set(val) {
// var hash = bcrypt.hashSync(val, saltRounds)
// return require('bcrypt').hashSync(val, 10)
var salt = bcrypt.genSaltSync(10)
var hash = bcrypt.hashSync(val, salt)
return hash
}
},
})
// create the model for users and expose it to our app
const User = mongoose.model('User', UserSchema)
// 删除用户集合
// User.db.dropCollection('users')
module.exports = { User }
@url=http://localhost:3001/api
@json=Content-Type: application/json
###
get {{url}}
###
post {{url}}
### 查询所有用户
get {{url}}/users
### 注册
post {{url}}/register
# Content-Type: application/json
{{json}}
{
"username": "user4",
"password": "123456"
}
### 登录
post {{url}}/login
{{json}}
{
"username": "user4",
"password": "123456"
}
### 个人信息
get {{url}}/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlNDc1ODcyOTM2Mjg2NWE0MDk4YmRhYSIsImlhdCI6MTU4MTczNTAyM30.Nm6UhPY7EfP-WQIDFldayXzFoJlt5oIgVhidzDPy0gc
其中遇到一个问题是,跟着视频使用bcrypt对用户密码进行散列加密时报错,换成bcryptjs库就OK了。
在VSCode中打开终端,进入EXPRESS-AUTH目录,执行nodemon .\server.js开启服务端,服务器会在对应的3001端口上监听客户端的http请求,然后打开test.http文件,在相应的登录、注册、查询所有用户的请求,使用Ctrl+鼠标单击按住Send Request,发起对应的get、post请求,其中登录的请求在VSCode中如下图所示: