---
# System prepended metadata

title: "\U0001F3C5 Day 33 - JWT 驗證 middleware"
tags: [2025 Node.js 後端工程師培訓營]

---

# 🏅 Day 33 - JWT 驗證 middleware

我們可以將 isAuth 作為 middlware，將需要登入後才能進入、操作的頁面或功能都帶入 isAuth middlware，確認使用者身份後再繼續執行

題目
---
根據需求，補上 `...` 的部分完整程式碼

1. 優化 `isAuth`，確認 token 存在並確認是否為 Bearer 開頭字串。
若符合此條件則取出 JWT 字串，若未成功取得 JWT，表示使用者可能尚未登入，需回傳 401 錯誤與錯誤訊息 `'使用者尚未登入！'`

    ```javascript=
    const isAuth = handleErrorAsync(async (req, res, next) => {
      // 確認 token 是否存在並取出 token
      let token;
      if (
        req.headers.authorization &&
        req.headers.authorization....('...')
      ) {
        token = req.headers.authorization.split(' ')[1];   
      }
      
      // token 不存在，回傳錯誤訊息
      if (!token) {
        return appError(...);
      }

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

      // 在資料庫尋找對應 id 的使用者
      const currentUser = await User.findById(decoded.id);

      // 在 req 物件加入 user 欄位，並由 next() 帶到 handleErrorAsync(async(req,res,next)=>{...})
      req.user = currentUser;
      next();
    });
    ```

2. 設計取得個人資料路由 `GET /users/profile`，加入 isAuth middleware，當 request 帶上的 token 驗證通過，就將取出的 user 資料回傳給 client
`routes/users.js`
    ```javascript=
    router.get('/profile', ..., handleErrorAsync(async (req, res, next) =>{
      res.status(200).json({
        status: 'success',
        user: ...
      });
    }))
    ```

## 回報流程

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

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

<!-- 解答：  
1. isAuth 
```javascript=
const isAuth = handleErrorAsync(async (req, res, next) => {
  // 確認 token 是否存在並取出 token
  let token;
  if (
    req.headers.authorization &&
    req.headers.authorization.startsWith('Bearer')
  ) {
    token = req.headers.authorization.split(' ')[1];   
  }

  // token 不存在，回傳錯誤訊息
  if (!token) {
    return appError(401, '使用者尚未登入！', next);
  }

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

  // 在資料庫尋找對應 id 的使用者
  const currentUser = await User.findById(decoded.id);

  // 在 req 物件加入 user 欄位，並由 next() 帶到 handleErrorAsync(async(req,res,next)=>{...})
  req.user = currentUser;
  next();
});
```

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


回報區
---
<!-- 
將答案貼至下方表格內，格式：
| Discord 暱稱 | [CodePen](連結) |
-->

|    Discord    |   CodePen ／ 答案  |
|:-------------:|:-----------------:|
|Tau| [CodePen](https://codepen.io/Tau-Hsu/pen/RNwGEya?editors=0010) |
| poyi | [CodePen](https://codepen.io/poyi-the-flexboxer/pen/XJWjwzb?editors=1010) |
| adengg | [CodePen](https://codepen.io/Osases/pen/OPJbLww?editors=0010) |
|janetlai|[CodePen](https://codepen.io/eiddkqxz-the-builder/pen/VYwmbwa?editors=0010)
|HarryKuo|[CodePen](https://codepen.io/harry_kuo/pen/XJWNaPy?editors=0010)|
|helena|[CodePen](https://codepen.io/helena27/pen/XJWgpgw)|
|hsin yu|[CodePen](https://codepen.io/tina2793778/pen/Byambrj)|