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

參考資料
- 1小時搞定NodeJs(Express)的用戶註冊、登錄和授權
- 全棧之巔-Node.js+Vue.js全棧開發深度愛好者和實踐者
- Express 4.x API
- Express中文官網
- NodeJs
- 菜鳥教程-Windows 平台安裝 MongoDB

