--- tags: Node.js 直播班 - 2023 春季班 --- # 🏅 Day 27 - JWT 產生身份驗證 token [JWT 流程圖](https://whimsical.com/jwt-UKUY1rj1vfoN6uyic7e4Sm) ![](https://i.imgur.com/C2fj19V.png) 當使用者登入或註冊,後端經過驗證後確認資料格式正確,就會產生一組的 token 回傳至使用者(client 端),此 token 用於身份驗證,接下來 client 端造訪需權限的頁面、發送需要權限的請求,若未帶上此 token 或是 token 驗證錯誤,都會請求失敗 接下來會使用 jsonwebtoken(JWT) 套件中的 `sign()` 實作產生 token 的流程(流程圖步驟 2) ```javascript const jwt = require('jsonwebtoken'); jwt.sign(payload, secretOrPrivateKey, \[options, callback\]) ``` - payload 會是一個物件,為該使用者的相關資訊(如 id) - secretOrPrivateKey 私鑰可以是字串、buffer 或物件,這裡會加入一段字串(如:`secret`)並設定為環境變數 `process.env.JWT_SECRET` - options 或 callback 函式,options 為一個物件,可根據文件中有提供的選項客製化,例如:設定此 token 的到期日 ```javascript const token = jwt.sign({id:id},process.env.JWT_SECRET,{ expiresIn: process.env.JWT_EXPIRES_DAY }); ``` 產生出的 token 會以 . 分隔,其中第一二段的 header 及 payload 都是可以透過 base64 編碼得知內容的 ``` eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9. # header eyJzdWIiOiIxMjM0NTY3ODkwIiwibmFtZSI6IkpvaG4gRG9lIiwiYWRtaW4iOnRydWV9. # payload TJVA95OrM7E2cBab30RMHrHDcEfxjoYZgeFONFh7HgQ # signature ``` ### 參考資源 - [jwt.sign()](https://github.com/auth0/node-jsonwebtoken#jwtsignpayload-secretorprivatekey-options-callback) - [什麼是 JWT](https://5xruby.tw/posts/what-is-jwt) ## 題目 延續前一天的每日任務,優化註冊功能,當使用者的資料都通過自訂的驗證條件,並成功新增使用者資料後,使用 `jwt.sign()` 產生 JWT,並回傳給 client(回傳內容須包含 token、使用者名稱 name) 回傳範例 ![](https://i.imgur.com/pvum5TA.png =600x) ## 回報流程 將答案連結貼至底下回報就算完成了喔! 解答位置請參考下圖(需打開程式碼的部分觀看) ![](https://i.imgur.com/vftL5i0.png) <!-- 解答: ```javascript 範例參考 https://github.com/gonsakon/express-week4-sample/blob/week6/routes/users.js router.post('/sign_up', handleErrorAsync(async(req, res, next) =>{ let { email, password, confirmPassword, name } = req.body; // 內容不可為空 if(!email||!password||!confirmPassword||!name){ 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)); } // 加密密碼 password = await bcrypt.hash(password,12); const newUser = await User.create({ email, password, name }); // 產生 JWT const token = jwt.sign({id:newUser._id},process.env.JWT_SECRET,{ expiresIn: process.env.JWT_EXPIRES_DAY }); // 將 token 回傳至 client res.status(200).json({ status: 'success', user:{ token, name: newUser.name } }); })) ``` --> 回報區 --- | 報數 | 組別/Discord 名字 | Codepen/HackMD/其他回饋 | |:----:|:-----------------------:|:-------------------------------------------------------------------------:| | 1 | 中 4 組 / jimkk159 | [HackMD - Day 27](https://hackmd.io/8IqjRhKNS0SY75Ne3Fevfw) | | 2 | 北 16 組 / 文文 | [HackMD - Day 27](https://github.com/chiawen81/nodeJS_DailyTasks_d20/tree/8dbd84fab6cabd474b57dc322591d0d9fedb4834) | | 3 | 北 13 組 / Louisa | [GitHub - Day 27](https://github.com/louisa0416/NodejsEnterpriseClass/tree/master/daily-task/day27) | | 4 | 南 1 組 / hiYifang | [HackMD - Day 27](https://hackmd.io/@gPeowpvtQX2Om6AmD-s3xw/S1WEL_yPc) |