---
# System prepended metadata

title: "\U0001F3C5 Day 29 - JWT 驗證"
tags: [Node.js 直播班 - 2023 春季班]

---

---
tags: Node.js 直播班 - 2023 春季班
---

# 🏅 Day 29 - JWT 驗證

[JWT 流程圖](https://whimsical.com/jwt-UKUY1rj1vfoN6uyic7e4Sm)

![](https://i.imgur.com/C2fj19V.png)

在前幾天的每日任務中，實做了註冊、登入功能，若成功註冊及登入的使用者會取得 JWT，也就是流程圖中的 1 - 3 步驟

接下來會實作 4 - 6 步驟，當需要登入才能造訪頁面或操作功能， client 端發出請求時就會需要在 header 的`Authorization` 帶上 JWT（`Bearer xxxxxx`)，並經由後端驗證

而後端驗證的部分會使用 jsonwebtoken 套件的 `vertify()` 方法
```javascript
const jwt = require('jsonwebtoken');
jwt.verify(token, secretOrPublicKey, [options, callback])
```
- token 為使用者夾帶需驗證的字串
- secretOrPublicKey 需帶入先前的環境變數 `process.env.JWT_SECRET`

因驗證 token 需要時間，jwt 這裡沒有提供 Promise，因此會需要另外使用 Promise 處理驗證結果
範例
```javascript
const decoded = await new Promise((resolve,reject)=>{
  jwt.verify(token,process.env.JWT_SECRET,(err,payload)=>{
    if(err){
      reject(err)
    }else{
      resolve(payload)
    }
  })
})
```

### 參考資源

- [jwt.verify()](https://github.com/auth0/node-jsonwebtoken#jwtverifytoken-secretorpublickey-options-callback)

## 題目
**將驗證 JWT 過程設計為一個 isAuth middleware，驗證前端傳送過來的 JWT，並回傳驗證成功訊息**

情境：當使用者發出 GET `/users/test` 請求時，需先以 `isAuth()` 驗證前端夾帶的 JWT 是否正確，若正確則回傳成功訊息
:::spoiler 回傳訊息參考
![](https://i.imgur.com/LKIZF8y.png)

:::


--
- 需使用先前完成的註冊功能，註冊一個測試的使用者資料，並成功取得回傳的 JWT
- 將此 JWT 帶入 isAuth middleware 驗證

**middleware 範例**
```javascript
const isAuth = handleErrorAsync(async (req, res, next) => {
  let token = // 請帶入註冊成功回傳的 JWT
  // 驗證 token 正確性
  
  /* 
    
    請在此參考上方做法驗證 JWT
   
  */
  
  // 
  const currentUser = await User.findById(/* 帶入驗證 token 解碼後取得的使用者 id */);
  // 在 req 物件加入 user 欄位，並由 next() 帶到 handleErrorAsync(async(req,res,next)=>{...})
  req.user = currentUser;
  next();
});
```
將 middleware 加入測試的 router 中
```javascript
// routes/users.js
router.get('/test', isAuth, handleErrorAsync(async(req,res,next)=>{
  res.status(200).json({
    status: 'success',
    user: req.user
  });
}))
```




## 回報流程

將答案連結貼至底下回報就算完成了喔! 
解答位置請參考下圖（需打開程式碼的部分觀看）

![](https://i.imgur.com/vftL5i0.png)

<!-- 解答：  

範例參考 https://github.com/gonsakon/express-week4-sample/blob/week6/service/auth.js
```javascript

// isAuth middleware
const isAuth = handleErrorAsync(async (req, res, next) => {
  let token = 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJpZCI6IjYyN2IxNTlhMDlhZmMwZTU4NzZiNTE5MSIsImlhdCI6MTY1MjIzMzkwMCwiZXhwIjoxNjYwMDA5OTAwfQ.07q6Ib5tSZ1CYJLg-SaGIdGUnuyDaHY6wX9NnuM23io' // 測試用 JWT

  // 驗證 token 正確性
  const decoded = await new Promise((resolve,reject)=>{
    jwt.verify(token,process.env.JWT_SECRET,(err,payload)=>{
      if(err){
        reject(err)
      }else{
        resolve(payload)
      }
    })
  })
  
  const currentUser = await User.findById(decoded.id);

  req.user = currentUser;
  next();
});



// routes/users 
router.get('/test', isAuth, handleErrorAsync(async(req,res,next)=>{
  res.status(200).json({
    status: 'success',
    user: req.user
  });
}))
```

-->



回報區
---

| 報數 |       組別／Discord 名字       |                            Codepen／HackMD／其他回饋                             |
|:----:|:-----------------------:|:-------------------------------------------------------------------------:|
| 1 | 中 4 組 / jimkk159 | [HackMD - Day 29](https://hackmd.io/ENpgxFVSTwuAGrBiF2rZpg) |
|  2  | 北 13 組 / Louisa  | [GitHub - Day 29](https://github.com/louisa0416/NodejsEnterpriseClass/tree/master/daily-task/day29) |
|  3  | 北 16 組 / 文文  | [GitHub - Day 29](https://github.com/chiawen81/nodeJS_DailyTasks_d20/tree/b7a751530ff1965f63a9eb2654f355fb9edfa06c) |
|  4  | 南 1 組 / hiYifang  | [HackMD - Day 29](https://hackmd.io/@gPeowpvtQX2Om6AmD-s3xw/S1WEL_yPc) |

