JWT Token 記住登入帳號 Remember me

驗證進階知識: JWT Token 記住登入帳號

JWT Token 沒有提供 Remember Token 的功能

若要在 JWT Token 提供 Remember Token 的功能,可以將儲存在 Cookie 的 JWT Token 時間效期拉很長,當 Cookie 存在就可以正常的去做驗證登入功能

使用 JWT Token Refresh Token 機制

JWT Token 會產生一個有效期的 Token,而 Token 中會包含以下欄位

欄位 說明
iat Token 產生時間
exp Token 最後可用時間,在此時間內 token 都可以重新 refresh 取得
nbf Token 有效時間,超過此時間 Token 會失效
/* eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2F1dGgua2VqeXVuLmNvbS9hcGkvdjEvdXNlci9hdXRoL2xvZ2luIiwiaWF0IjoxNjIxMzIyMDg2LCJleHAiOjE2MjE0MDg0ODYsIm5iZiI6MTYyMTMyMjA4NiwianRpIjoiSzRzbzNmeWJsMjBjUnFjeCIsInN1YiI6InVzZXItc2V1azU4ODN6bXY1YXV1In0.EeB6mb-XWU9Yhq9UroKeI6SNiiC6taa7Jo5FF8jzrhc
*/
{
  "iss": "https://auth.kejyun.com/api/v1/user/auth/login",
  "iat": 1621322086,
  "exp": 1621408486,
  "nbf": 1621322086,
  "jti": "K4so3fybl20cRqcx",
  "sub": "user-seuk5883zmv5auu"
}

exp 欄位時間會大於或等於 nbf時間,當時間超過 nbf 時間時此 Token 會無法使用,但若 nbf 時間在 exp 時間內,可以重新使用 refresh 的方式再取得有效的 Token,直到時間超過 exp 為止

此 Token 會透過 JWT 金鑰去驗證資料是否有被串改過,所以可以保護 Token 的安全性,所以可以將 JWT Token 的過期時間 nbf 設定為比較短,而 JWT Token 可用時間 exp 設定長一點,當 Token 過期可以重新得去 Refresh Token 就可以持續不斷延長 Token 可用時間

步驟 流程 用途
1 傳入帳號密碼驗證 驗證帳號密碼是否正確,資料庫是否有此帳號
2 記錄使用者 user_id 到 JWT Token Cookie 告訴前端此使用者的身份是誰,之後會透過這個含有 user_id 的 JWT Token cookie 做驗證
3 透過含有 user_id 的 JWT Token Cookie 做其他驗證請求 使用金鑰驗證 Token 是否合法沒有被串改,驗證合法則撈取 JWT Token Cookie 中的 user_id 撈取使用者資料
4 呼叫 Refresh Token API 取得新的 JWT Token 儲存至 Cookie 若 JWT Token 失效,但 exp 還在效期內,重新 Refresh 取得新的 Refresh JWT Token
5 使用新的 JWT Refresh Token 做驗證請求 透過新的 Refresh Token 重新驗證取得登入使用者資料

JWT Token 效期過長安全性問題

當將 JWT Token 效期設定比較長,可以達到記住登入使用者帳號,讓使用者保持隨時是登入的狀態,但若時間設定過長(e.g. 3 年、5 年)則 Token 安全性會有問題,若此 Token 被劫取走,在這個這麼長的有效期限內,此 Token 都會是有效的可以合法的存取 API

JWT Token 加入 remember_token

在使用者資料表加入一個 remember_token 的欄位,當作幫使用者做重新產生 JWT Token 驗證的動作,所以登入流程會變成

步驟 流程 用途
1 傳入帳號密碼驗證 驗證帳號密碼是否正確,資料庫是否有此帳號
2 產生新的 remember_token 記錄到使用者資料表的 remember_token 欄位 做為之後驗證重新登入用
3 記錄使用者 user_id 及 remember_token 到 JWT Token Cookie 告訴前端此使用者的身份是誰,之後會透過這個含有 user_id 的 JWT Token cookie 做驗證
4 透過含有 user_id 及 remember_token 的 JWT Token Cookie 做其他驗證請求 使用金鑰驗證 Token 是否合法沒有被串改,驗證合法則撈取 JWT Token Cookie 中的 user_id 撈取使用者資料
5 呼叫 Refresh Token API 取得新的 JWT Token 儲存至 Cookie 若 JWT Token 失效,但 exp 還在效期內,重新 Refresh 取得新的 Refresh JWT Token
6 使用新的 JWT Refresh Token 做驗證請求 透過新的 Refresh Token 重新驗證取得登入使用者資料
7 透過 remember_token 及 user_id 的 Cookie 做重新取得新 JWT Token 撈取 JWT Cookie 中的 remember_token 及 user_id,與資料庫做比對,確認是否 token 合法可以正常重新產生
8 使用新產生的 JWT Token 做驗證請求 透過新產生的 JWT Token 重新驗證取得登入使用者資料
/* eyJ0eXAiOiJKV1QiLCJhbGciOiJIUzI1NiJ9.eyJpc3MiOiJodHRwczovL2F1dGgua2VqeXVuLmNvbS9hcGkvdjEvdXNlci9hdXRoL2xvZ2luIiwiaWF0IjoxNjIxMzIyMDg2LCJleHAiOjE2MjE0MDg0ODYsIm5iZiI6MTYyMTMyMjA4NiwianRpIjoiSzRzbzNmeWJsMjBjUnFjeCIsInN1YiI6InVzZXItc2V1azU4ODN6bXY1YXV1IiwicmVtZW1iZXJfdG9rZW4iOiJyYW5kb20tcmVtZW1iZXItdG9rZW4ifQ.GoW1zQ70ncIox--G1zrurNhEmTTpqWV_2d-2gWWWsow */
{
  "iss": "https://auth.kejyun.com/api/v1/user/auth/login",
  "iat": 1621322086,
  "exp": 1621408486,
  "nbf": 1621322086,
  "jti": "K4so3fybl20cRqcx",
  "sub": "user-seuk5883zmv5auu",
  "remember_token" : "random-remember-token"
}

當 JWT Token 效期時間很短時(例如 300 分鐘),在 JWT Token 過期時,也可以透過 Cookie 中的 remember_token 去重新驗證並產生新的 JWT Token 回傳給使用者,讓使用者可以持續使用合法的 JWT Token 不斷做存取

remember_token 安全性

因為只要 JWT Token Cookie 過期時間設定的夠長,只要一直有 remember_token,則使用者就可以一直無限期的一直不斷的維持登入狀態,這樣可能會有安全性的問題,所以在使用者自己觸發登出時,記得更新儲存在資料庫的 remember_token,讓其他有此 remember_token 的使用者無法繼續登入

參考資料