使用NodeJs(Express)搞定用戶註冊、登錄、授權

  • 2020 年 2 月 23 日
  • 筆記

前言

首先做一下聲明,本篇部落格來源於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服務。

編碼前的準備工作:第三方庫和rest-client插件安裝

我的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介面文件

server.js

/* 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')  })

model.js

/* 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 }

test.http

@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中如下圖所示:

參考資料

Tags: