重要说明
首先是初始化我们的项目,
- 项目的初始化
如下是我们的项目文件夹结构
![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\1589190039(1).jpg)
- 项目的包管理
npm install express@next
npm install mongoose
npm install bcrypt
npm install jsonwebtoken
好了以上就是我们需要做的
设计路由逻辑
- 测试接口
- 注册接口
- 登录接口
- 获取所有用户信息接口
- 等录之后的权限校验接口
- 构建入口,并且完成json的解析
/app.js
const express = require('express');
const app = express();
//解析一遍post参数
app.use(express.urlencoded({ extended: true }))
app.use(express.json())
//路由分发器
app.get('/test', async(req, res) => {
res.send('测试打通!没问题')
})
app.use('/api', require('./route/index'))
app.listen(3001, async() => {
console.log('http://localhost:3001');
})
- 构建分路由
/router/index.js
const express = require('express');
const indexApi = express.Router()
indexApi.post('/register', async(req, res) => {
console.log(req.body);
res.send('register!!ok')
})
indexApi.post('/login', async(req, res) => {
console.log(req.body);
res.send('login!!ok')
})
indexApi.get('/users', async(req, res) => {
res.send('users!!ok')
})
indexApi.get('/profile', async(req, res) => {
res.send('profile!!ok')
})
- 完成对应的接口测试
/.http
@uri = http://localhost:3001/api
### 测试
GET {{uri}}
### 展示出所有的用户
GET {{uri}}/users
### 注册
POST {{uri}}/register
Content-Type: application/json
{
"username":"user2",
"password":"123456"
}
### 登录
POST {{uri}}/login
Content-Type: application/json
{
"username":"user2",
"password":"123456"
}
### 获取个人信息,传递的是当前保持状态了的用户
GET {{uri}}/profile
Authorization: Bearer eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlYjhhNDIzOTM4YzdhNmQ3NDg5ZDJlMyIsImlhdCI6MTU4OTE2MDY0Nn0.UeSGbDgUrQaThemD18iIAGW6t-lc8R_R5tDvFamrgDw
设计实现数据库Model
- 使用mongoose连上数据库
- 创建shcema规则
- 使用规则创建集合
- 倒出集合操作对象,创建集合交给理由或者中间件去做,这里功能比较简单我们可以直接丢给路由去做,但是为了保持编程的风格一致,我打算丢到中间件里面去
/model/model.js
const mongoose = require('mongoose');
const bcrypt = require('bcrypt');
mongoose.connect('mongodb://localhost:27017/express-auth', { useUnifiedTopology: true, useNewUrlParser: true, useCreateIndex: true });
const UserSchma = new mongoose.Schema({
username: {
type: String,
unique: true //只需要usernam为唯一值
},
password: {
type: String,
}
})
const User = mongoose.model('User', UserSchma) //虽然这个表的名字是User但是实际上数据库创建的时候会给你变成users
// 倒出数据操作对象
module.exports = { User }
实现新增(实际上就是注册)用户接口
const { User } = require('../model/model')
module.exports = {
register: async(req, res, next) => {
// console.log(req.body);
let { username, password } = req.body
const user = await User.create({
username: username,
password: password
})
req.user = user
next()
}
}
const users = require('../middleware/users')
+++
indexApi.post('/register', users.register, (req, res) => {
res.send(req.user)
})
+++
实现展示用户功能
/middleware/users.js
+++
//查看所有用户
showUser: async(req, res, next) => {
//为什么是find就可以了,因为mongoose给你封装了
const user = await User.find();
req.user = user;
next();
}
+++
/router/index.js
const users = require('../middleware/users')
+++
indexApi.get('/users', users.showUser, async(req, res) => {
res.send(req.user)
})
+++
实现bcrypt加密密码
+++
password: {
type: String,
set(val) { //val是自定义的保存前的加密,返回的值就是加密之后的密码
return require('bcrypt').hashSync(val, 10) //进行散列之后的密码,10就是加密强度
}
}
+++
加密之后的密码验证怎么做?实际上这里就是登录功能
/middleware/users.js
+++
//登录器
login: async(req, res, next) => {
let { username, password } = req.body
const user = await User.findOne({
username: username
})
//验证用户名
if (!user) {
return res.status(422).send({ message: '用户名不存在' })
}
const isPasswordValid = bcrypt.compareSync(password,
user.password
)
//验证密码
if (!isPasswordValid) {
return res.status(422).send({ message: '密码无效' })
}
req.user = user
next()
}
+++
/router/index.js
indexApi.post('/login', users.login, async(req, res) => {
res.send(req.user)
})
实现token的下发
这里的业务逻辑核心,其实就是这个token该如何加
- 修改一下我们的登录功能,使得用户登录的时候加上一个用以验证用户登录状态的token
/middleware/users.js
+++
const jwt = require('jsonwebtoken')
+++
+++
//登录器
login: async(req, res, next) => {
+++
//生成token,jwtToken
//生成签名,我们给id丢进去据好了
const token = jwt.sign({
//加密的签名
id: String(user._id),
//密钥
}, 'asdasdasdasdasdasdasdasdasdasdasd') //这个东西实际上是一串秘钥,用来对应每一个的tonken验证器,它应该被写一个单独的文件里
res.user = {
user,
token
}
+++
}
- 我们看一些测试的结果
{
"user": {
"_id": "5eb933c9cf3c3f33fcadb560",
"username": "user2",
"password": "$2b$10$n2OHQzuSuUtwWpg.YuiDO.FPM4Q9nrBdqANLB3Wkh67P.MonpIyYi",
"__v": 0
},
"token": "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjVlYjkzM2M5Y2YzYzNmMzNmY2FkYjU2MCIsImlhdCI6MTU4OTE5Nzc4MX0.a4vrQwTeGsuI320m1OYsjSB8abdxxm8TReKYg6UKbVQ"
}
实现用户的token校验.
const jwt = require('jsonwebtoken')
const { User } = require('../model/model')
module.exports = {
auth: async(req, res, next) => {
//注意啊这个字段是我们前端需要实现的,因为这是后台要求的
let raw = String(req.headers.authorization).split(' ').pop() //我为啥要用空格分隔,因为我发起请求的时候多加了一个字段,
const tokenData = jwt.verify(raw, 'asdasdasdasdasdasdasdasdasdasdasd')
let { id } = tokenData
//加到req上以便以给下一个中间件使用
req.user = await User.findById(id)
next()
}
}
//核心token验证器
indexApi.get('/profile', auth.auth, async(req, res) => {
res.send(req.user)
})
注意,以上的所有都只是一个小小的demo。正式的打包再我这里
整理好所有的目录,打包构建成蓝图并且发布上git
- 我为什么要整理成蓝图?因为我希望我的token验证其能复用到很多地方去,假设我以后的项目需要用这个那么我就直接下载蓝图,这样我的token就不用我再去啰嗦的写了,这也实际上已经是一个初步的node框架的雏形了。
- 优化目录结构
- 整理接口 去掉了没有用的接口,只保留了一些基础的接口
- 使用说明:你只需要npm install 就能实现token的验证了,需要验证之后的接口请在admin之后的路由书写,当然你可以自定义路由,拿着我的auth去做验证就可以了
- 建议你使用非对称加密的密钥对,进行token的加密,你可以通过引入文件去配置你的加密信息