藍圖blueprint,git地址:https://github.com/BM-laoli/Node-token-forApi-blueprint
重要說明
這個輪子是 使用 express@5.0 + MongoDB構建起來的一個 node后台通用的驗證器,里面主要講的就是使用jwt,token進行驗證,當然你想使用session也沒問題,但是這個藍圖工程只包含了token字段內容
首先是初始化我們的項目,
主要是 安裝一些東西
- 項目的初始化
如下是我們的項目文件夾結構
.jpg)
- 項目的包管理
首先我們需要使用express@next框架,因為只用next才能在里面使用async es7的一些東西,
我們還需要mongoose來操作數據庫
我們還需要bcrypt對數據庫里面的密碼進行加密
我們還需要jsonwebtoken快捷的生成token
npm install express@next
npm install mongoose
npm install bcrypt
npm install jsonwebtoken
好了以上就是我們需要做的
設計路由邏輯
首先我們需要在這里設計幾個接口,他們是,並且完成post請求的配置解析json
- 測試接口
- 注冊接口
- 登錄接口
- 獲取所有用戶信息接口
- 等錄之后的權限校驗接口
- 構建入口,並且完成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去驗證,目的就是模塊化處理業務,請求主頁不需要token請求管理的頁的接口就需要驗證
/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,比如與用戶相關的molde都放在一個文件里,等等
/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 }
注意啊,我們只是定義的集合還有數據庫的表(集合)操作對象,還米有拿去業務中使用,接下里的章節我們會拿到具體的業務里去使用
好了我們階段性的回顧一下我們現在的文件夾里面都有哪些東西吧
實現新增(實際上就是注冊)用戶接口
這里我們定義就能實現我們的業務功能了,首先要說明的是,我們這里依然使用標准化的項目開放方式,把功能寫在中間件里,
這里的定義的中間件處理一個專門的業務就是User相關的業務,這是我工作中編寫nodejs的全棧項目的一個習慣
/middleware/users.js
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)
})
+++
實現展示用戶功能
前面我們實現了用戶的注冊新增功能,那么我們就來實現一些查看所有用戶功能。
用了前面的架構模式,我們的這個業務就可以全部寫在middelwear里了,如果有設計賦值的操作。我們還可以創建一個工具middlewear,來幫助我們實現復雜的功能,這就是模塊化開發
/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加密密碼
實際上實現bcrypt的加密非常的簡單,只需要調用方法就好了
+++
password: {
type: String,
set(val) { //val是自定義的保存前的加密,返回的值就是加密之后的密碼
return require('bcrypt').hashSync(val, 10) //進行散列之后的密碼,10就是加密強度
}
}
+++
加密之后的密碼驗證怎么做?實際上這里就是登錄功能
實際上也非常的簡單,先驗證用戶名是否正確 如果正確就去根據用戶名查用戶數據,然后拿到加密之后的密碼,然后使用bcrypt自己的驗證方式去驗證就好了
/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該如何加
- 修改一下我們的登錄功能,使得用戶登錄的時候加上一個用以驗證用戶登錄狀態的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校驗.
這里我們把auth做成一個中間件,這個中間件可以加載需要驗證的路由的前面,如果通過驗證就放行,要不然就放行next,這就是驗證器auth的實現原理,非常的簡單
/middleware/auth.js
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()
}
}
假設我們現在需要把這個auth用於我們的 profile接口做驗證,那么我們可以這樣來使用
//核心token驗證器
indexApi.get('/profile', auth.auth, async(req, res) => {
res.send(req.user)
})
注意,以上的所有都只是一個小小的demo。正式的打包再我這里
整理好所有的目錄,打包構建成藍圖並且發布上git
- 我為什么要整理成藍圖?因為我希望我的token驗證其能復用到很多地方去,假設我以后的項目需要用這個那么我就直接下載藍圖,這樣我的token就不用我再去啰嗦的寫了,這也實際上已經是一個初步的node框架的雛形了。
我把它寫在了blueprint_for_token_v3中。你可以直接git clone去使用它構建你的node項目
優化項目結構打包,我做了那些事?(主要就是以下愛的事情)
- 優化目錄結構
- 整理接口 去掉了沒有用的接口,只保留了一些基礎的接口
- 使用說明:你只需要npm install 就能實現token的驗證了,需要驗證之后的接口請在admin之后的路由書寫,當然你可以自定義路由,拿着我的auth去做驗證就可以了
- 建議你使用非對稱加密的密鑰對,進行token的加密,你可以通過引入文件去配置你的加密信息