JWT 介紹
JWT 運作原理
當使用者傳送post request 到伺服器時,伺服器會產生Json Web Token用來加密使用者傳來的資料,並使用 secrest key來加密。
加密完後就會將JWT回傳給瀏覽器,瀏覽器可以選擇各種儲存token的方式例如cookie。
當使用者再次發出request請求時,會在header附帶上JWT token,伺服器收到token後會使用 同樣secrest key來進行解密,確認token的資料是否一樣。確認token沒問題後,就可從token中取得user的資料,例如帳密,再回傳給前端。
和session的差異
session運作的原理和jwt類似,但主要差別是,session會儲存user資料在伺服器,伺服器利用session id來尋找user資料。
jwt則將使用者資料存在token裡,token則會被保存在前端,伺服器不用儲存任何資料。也就是說,可以使用同樣的token在不同的伺服器上,不像session可能遇到不同伺服器有不同session而無法登入的情況。
JWT 加密過程
左欄是加密後的JWT TOKEN,右欄則是解密後的token,解密後的token分為三部分:
- HEADER: 包含用來加密、解密的演算法。
- PAYLOAD: 儲存在token裡的資料。
- VERIFY SIGNATURE: 用來驗證token是否被使用者更改。
使用base64URL來加密或解密HEADER跟PAYLOAD,並使用secret Key來加解密,也就是左欄紅色跟紫色的密碼。
實際流程: 當伺服器收到jwt token後,會將左欄紅色跟紫色的密碼,用指定的演算法(上圖是HS256)來hash,並確認hash後的值是否等於最後一段藍色的密碼。
實戰加密流程
安裝套件
在node.js專案中,先下載套件 jsonwebtoken
1 | npm install --save jsonwebtoken |
在 controller 裡引入jwt
1 | const jwt = require('jsonwebtoken'); |
後端加密
1 | const login = async (req, res) => { |
使用 jwt.sign()
來加密,加密完後將token回傳給前端。
1 | jwt.sign({ payload }, 金鑰, { expiresIn : 過期時間} ) |
- 第一個參數為 payload: 使用者和相關的資訊都可以放置其中(ex: id、name)。
- 第二個是金鑰字串,通常會是複雜的字串存在.env檔裡
- 第三個可傳入 token 過期時間
不要將隱私資訊存放在 Payload 當中, Payload 和 Header 被轉換成 Base64 編碼後,能夠被輕易的轉換回來
因此不應該把如用戶密碼等重要資料存取在 Payload 當中
前端接收token
前端發出網路請求後成功後(例如登入成功),會收到後端回傳的token,前端可以先存入 localStorage
1 | const { data } = await axios.post('/api/v1/login', { username, password }) |
當再次發出的請求是需要驗證時,需要傳token給後端驗證。在HEADER中使用Authorization並帶入存取的Token
1 | const token = localStorage.getItem('token') |
後端接收token
當後端收到前端帶有token的請求後,可以從 req.headers.authorization
裡收到token的值。
1 | { |
用split方法取得 Bearer 後面的token字串
1 | const authHeader = req.headers.authorization; |
取得 token字串後,可以用 jwt.verify(token, 金鑰)
來解析
1 | const decoded = jwt.verify(token, process.env.JWT_SECRET); |
當token解析符合金鑰字串時,就會將當初加密的物件(payload)解析出來:
1 | { |