這是在講關於一名叫 Koa 的全端勇士傳說-會員登入機制(2)

前言

前面大致上將登入方面的介面以及基本的功能都做好了,接下來要來講關於會員密碼的部份

會員密碼加密

要製作會員登入之前必須先來講講 會員密碼加密,那麼什麼是加密呢?

通常我們存入資料庫中比較敏感的東西就會做加密的動作,假使資料庫被害了至少使用者密碼沒辦法被看光,所以在實作之前一定要考慮清楚哪些是屬於必須加密的資料

起手式

在這邊將會使用到一個加密套件叫做 bcrypt,所以先來安裝套件吧

1
npm install --save bcrypt

接下來在 router 中引用 bcrypt

1
const bcrypt = require('bcryptjs');

設置加密的強度,通常會設置長度 10

1
const salt = bcrypt.genSaltSync(10);

最後新增一個 router 專門來接收註冊的資料

1
2
3
4
5
6
7
8
9
10
11
12
router.post('/signup', async(ctx, next) => {
const password = ctx.request.body.password;
const newPassword = bcrypt.hashSync(password, salt); // 加密
var modelDate = {
account: ctx.request.body.email,
email: ctx.request.body.email,
password: newPassword,
createdAt: new Date(),
};
await models.Account.create(modelDate);
ctx.redirect('/admin/login');
})

接下來就可以試著註冊帳號看看,成功的話就可以看到資料庫密碼欄位是加密的狀態唷~

加密

登入驗證

那麼驗證部分呢?驗證部分將會使用 bcrypt.compareSync

1
2
3
4
5
6
7
8
9
10
11
12
13
router.post('/login', async(ctx, next) => {
const account = ctx.request.body.email;
const password = ctx.request.body.password;
models.Account.findOne({
where: {account: account}
}).then((result) => {
if(bcrypt.compareSync(password ,result.password)) {
console.log('密碼正確')
} else {
console.log('密碼錯誤');
}
})
})

如果輸入的密碼是正確的就會顯示密碼正確,如果輸入錯誤就會得到密碼錯誤,那麼由於我們密碼是註冊 123456,如果正確就會得到密碼正確

密碼正確

但是如果我們輸入錯誤的密碼呢?例如 123456789 呢?那麼就會得到密碼錯誤

密碼錯誤

那麼我們就可以來修改成當密碼正確時就紀錄 session 並導向到登入頁面顯示使用者 Email

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
router.post('/login', async(ctx, next) => {
const account = ctx.request.body.email;
const password = ctx.request.body.password;
models.Account.findOne({
where: {account: account}
}).then((result) => {
if(bcrypt.compareSync(password ,result.password)) {
ctx.session.uid = result.email;
ctx.redirect('/admin');
} else {
console.log('密碼錯誤');
ctx.redirect('/admin/login');
}
})
})

接下來就可以試著登入看看是否可以進去該頁面哩

登入成功

而這邊的 router 如下

1
2
3
4
5
6
7
8
9
10
11
12
.get('/', async (ctx, next) => {
const uid = ctx.session.uid;
console.log(uid);
if(uid){
await ctx.render('dashboard',{
title: '登入成功!',
uid
})
} else {
ctx.redirect('/admin/login');
}
})

但是這邊其實還要做一下修改比對,如果 session 並不存在呢?所以可以搭配資料庫查詢來查詢是否真的有這個使用者存在

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
router.get('/', async (ctx, next) => {
const uid = ctx.session.uid;
if (uid) {
await models.Account.findOne({
where: { account: uid }
}).then(async (result) => {
if (uid === result.account) {
await ctx.render('dashboard', {
title: '登入成功!',
uid
})
} else {
ctx.redirect('/admin/login');
}
})
} else {
ctx.redirect('/admin/login');
}
})

那麼這邊以上就是一個簡易的會員登入與註冊的機制哩~

補充

最後補充一個登出的 router,登出的 router 很簡單,將 session 清空就好哩

1
2
3
4
5
6
7
router.post('/signout', async (ctx, next) => {
ctx.session.uid = '';
ctx.body = {
message: '登出成功',
url: '/admin/login'
}
})

主要會透過 AJAX 方式登出,所以這邊也提供原生登出&轉址

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
const signout = document.querySelector('#signout');
signout.addEventListener('click', (e) => {
e.preventDefault();
fetch('/admin/signout', { method: 'post' })
.then((response) => {
return response.json();
})
.then((result) => {
console.log(result);
window.location.href = result.url;
})
.catch((error) => {
console.log(error);
})
})