# 【Day 26】bcrypt.js 密碼加解密
## :herb: <font color="#E58638">講義內容</font>
**密碼加密**
使用 bcrypt.js 的 `hash()` 以非同步的方式將密碼加密
```javascript
bcrypt.hash(password,12);
// 第一個參數是要做雜湊加密的字串,第二個參數是要加鹽的字串長度
```
補充:
[雜湊(Hash function)](https://zh.wikipedia.org/zh-tw/%E6%95%A3%E5%88%97%E5%87%BD%E6%95%B8)為一種演算法,會將資料打亂建立雜湊值,雜湊值具有「不可逆」的性質(由此值回推原本的值非常困難),因此常用於密碼加密
[鹽(Salt)](https://zh.wikipedia.org/zh-tw/%E7%9B%90_(%E5%AF%86%E7%A0%81%E5%AD%A6))在密碼學中,是指在雜湊之前將雜湊內容(例如:密碼)的任意固定位置插入特定的字串。這個在雜湊中加入字串的方式稱為「加鹽」
**密碼解密**
密碼加密後,未來需要驗證是否為該註冊帳號就需以 `compare()` 將密碼與加密後的字串進行比對
```javascript
bcrypt.compare(password, user.password);
// 第一個參數是接收到的密碼,第二個參數是由資料庫找出的該 user 的密碼,為雜湊加密的字串
```
### 參考資源
[bcrypt.js - hash](https://github.com/dcodeIO/bcrypt.js#hashs-salt-callback-progresscallback)
[bcryptjs - compare](https://github.com/dcodeIO/bcrypt.js#compares-hash-callback-progresscallback)
### 題目(將答案寫在 GitHub 並提交至回報區)
測試註冊功能 POST `/users/sign_up`,使用[第五週專案](https://github.com/gonsakon/express-week4-sample/tree/week5) 練習(接下來會以此專案陸續練習第六週的內容)
- 於 models/user.js 加入使用者資料 schema,以儲存使用者 email 暱稱 密碼(可參考第六週[範例](https://github.com/gonsakon/express-week4-sample/blob/week6/models/usersModel.js))
- 安裝 [bcryptjs](https://www.npmjs.com/package/bcryptjs) 套件,使用 bcrypt.js 的 `hash()` 將 client 端傳送的密碼經過雜湊再儲存至資料庫
```javascript
router.post('/sign_up', handleErrorAsync(async(req, res, next) =>{
let { email, password, confirmPassword, name } = req.body;
// 加密密碼
password =
const newUser = await User.create({
email,
password,
name
});
res.status(200).json({
status: 'success',
data: newUser
});
}))
```
測試註冊 API `/users/sign_up` 並取得加密後的密碼
範例
![](https://i.imgur.com/iVkplJW.png =500x)
---
## :herb: <font color="#E58638">作業回報</font>
- [Github](https://github.com/hobbyling/metawall-backend/blob/main/controllers/userController.js)
- 註冊 API
```javascript
// 註冊
async signUp(req, res, next) {
let { name, email, password, confirmPassword } = req.body
// 內容不可為空
if (!name || !email || !password || !confirmPassword) {
return next(appError(400, '欄位未填寫正確', next))
}
// 密碼不一致
if (password !== confirmPassword) {
return next(appError(400, '密碼不一致', next))
}
// 密碼至少 8 個字元
if (!validator.isLength(password, { min: 8 })) {
return next(appError(400, '密碼字數少於 8 碼', next))
}
// Email 格式錯誤
if (!validator.isEmail(email)) {
return next(appError(400, 'Email 格式錯誤', next))
}
// Email 是否已被註冊過
// 先在資料庫尋找是否已存在 email
const isRegister = await User.findOne({ email }).count()
if (isRegister === 0) {
// 密碼加密
password = await bcrypt.hash(password, 12)
const newUser = await User.create({
name,
email,
password
})
generateSendJWT(newUser, 201, res)
} else {
return next(appError(400, '此 Email 已註冊過', next))
}
},
```
- Postman 實際操作
![Postman 實際操作](https://i.imgur.com/cnqn4u4.png)
---
###### tags: `Node.js 直播班 - 2022 春季班`