這個輪子是 使用 express@5.0 + MongoDB構建起來的一個 node後臺通用的驗證器,裏面主要講的就是使用jwt,token進行驗證,固然你想使用session也沒問題,可是這個藍圖工程只包含了token字段內容前端
主要是 安裝一些東西node
以下是咱們的項目文件夾結構git
![img](file:///C:\Users\ADMINI~1\AppData\Local\Temp\1589190039(1).jpg)web
首先咱們須要使用express@next框架,由於只用next才能在裏面使用async es7的一些東西,
咱們還須要mongoose來操做數據庫
咱們還須要bcrypt對數據庫裏面的密碼進行加密
咱們還須要jsonwebtoken快捷的生成tokenmongodb
npm install express@next npm install mongoose npm install bcrypt npm install jsonwebtoken
好了以上就是咱們須要作的shell
首先咱們須要在這裏設計幾個接口,他們是,而且完成post請求的配置解析json數據庫
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請求管理的頁的接口就須要驗證express
/router/index.jsnpm
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') })
@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都寫在一個文件裏有點不太穩當,固然這樣作是徹底沒有問題的,若是項目有良好的架構咱們能夠後期考慮把他們分類的去構建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的加密很是的簡單,只須要調用方法就行了
+++ 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該如何加
+++ 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" }
這裏咱們把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。正式的打包再我這裏
我把它寫在了blueprint_for_token_v3中。你能夠直接git clone去使用它構建你的node項目
優化項目結構打包,我作了那些事?(主要就是如下愛的事情)