[專案紀錄] 記帳 web app 升級!實作登入功能 — (一) 註冊篇

I caught a code
I Caught a Code
Published in
6 min readMar 19, 2021

初診請填病歷表,初次使用請註冊~

以鳴人作為主題的記帳 web app

Live Demo on Heroku (先註冊一個帳號就能使用囉)

延續上個學期用 Express.js 做的基本 CRUD 記帳本專案,這次要來加入 登入/登出與保持狀態的機制,使功能更加完整。先來說說這次的專案升級架構:

架構規劃

希望打造功能

  1. 註冊功能
  2. 打造 登入/登出功能
  3. 驗證登入狀態,取得訪問權限

流程概述

畫圖順一下我對註冊/登入/登出 機制的理解:

簡述 註冊/登入/登出 背後的概念

選擇實作套件

  1. Mongoose — 使用 MongoDB 資料庫儲存、調用使用者資訊
  2. Passport.js — 打造驗證使用者機制
  3. Express-session — 打造驗證狀態機制
  4. bcrypt.js — 密碼加密

那麼就開始吧~

設定 登入/登出 路由

要做到登出/登出/註冊功能,勢必要準備相對應的頁面,因此路由規劃如下:

GET /users/register → 註冊頁面GET /users/login → 登入頁面POST /users/register → 註冊POST /users/login → 登入GET /users/logout → 登出

到 routes/modules 下新增名為 users.js 的 router module,增加上述的路由,並到之前寫好的總路由器 index.js 中掛載

新增 登入/註冊頁面

這邊使用的是 Handlebars 樣板引擎,新增 login.handlebars 、 register.handlebars 兩個頁面,為了讓第一次使用的人能夠註冊,在表單下方加入能在兩個頁面間互相訪問的連結 login 與 register:

決定註冊資訊欄位與設計 User Model

註冊表單有的項目,在資料庫儲存的資料也必須要有,因此在 models/ 下新增 user.js,設定 User model:

const mongoose = require('mongoose')
const Schema = mongoose.Schema
const userSchema = new Schema({
name: {
type: String,
required: true
},
email: {
type: String,
required: true
},
password: {
type: String,
required: true
},
createdAt: { // 方便記錄此使用者是何時註冊,目前還沒要拿來幹嘛
type: Date,
default: Date.now
}
})
module.exports = mongoose.model('User', userSchema)

實作註冊

其實 註冊 就是在使用者提交 name, email, password 等資訊之後,將這包資料儲存進我們的資料庫,方便日後登入驗證時,到資料庫中尋找是否已存在該位使用者,若 放行;若無→ 請註冊。我把這個流程想像是 到診所看病,初診的人需要先填病歷表,而複診的人因為已經在診所資料庫中擁有病歷資料,所以可以直接進去看病。

因此註冊流程簡單來說就是:跟使用者要資料 → 將資料存入資料庫中

實作程式碼如下,順便加入了一些欄位驗證機制,以及密碼加密 (利用 bcrypt.js 套件) 的動作:

簡單說明下:當使用者提交表單資訊後,後端會驗證提交的資訊是否與 先前設定的 User model 項目性質相符,再來到資料庫中以 email 為 index 來尋找是否已有註冊過。若有→回到登入頁面,請使用者換別的 email 註冊;若無將使用者設定的密碼加密後,再整包資料存入資料庫中,最後才重新導向登入頁。

這邊使用 /作為重新導向的路由,照理來說會導到首頁,但因為之後會加入登入狀態的驗證機制,因此註冊完還是會要求使用者先登入才能訪問首頁。

註冊後會直接倒回登入頁

這樣註冊的部分就完成了~

補充:密碼加密

除了註冊的流程以外,值得一提的部分是關於密碼加密的部分。一開始提到使用者將註冊資訊,包含註冊用的 email 與 password 提交到後端資料庫中做儲存,但萬一資料庫被駭,駭客就能一覽無遺這些使用者的密碼了,因此資安風險相當高。這時候若能將密碼等敏感資訊進行加密,安全度也會大大提升。

而這次選用的加密套件是 bcrypt.js,原理簡單來說就是在 原本的密碼加上一段隨機字串 (salt),也就是 bcrypt 內建方法中的 genSalt(),再放進 bcrypt.hash() 中進行雜湊 (hash),再將雜湊的結果與加入的 salt 分開儲存。而雜湊法雖不可逆,但也能用窮舉法去列出一個對照表,因此利用分開儲存的方式,避免駭客用這些方式去解析密碼。

取自 Alpha Camp 教案

文章參考:

Adding Salt to Hashing: A Better Way to Store Passwords

Facebook admits it insecurely stored ‘millions’ of Instagram passwords in plaintext

註冊就講到這邊,下篇直接進入 登入/登出 機制的實作!

--

--