iT邦幫忙

2023 iThome 鐵人賽

DAY 22
0

https://ithelp.ithome.com.tw/upload/images/20230925/20136558heIfon9aEL.jpg
還記得我們在[Day11] 登入、註冊API開發和HTTP Authentication(JWT)有介紹過整個登入到授權的流程。

  1. 使用者送出認證資料(Login):通常是帳號和密碼。
  2. 伺服器驗證:伺服器收到使用者送出的認證資料後,會根據其儲存的資料進行驗證。
  3. 生成JWT:如果認證成功,伺服器會生成一個JWT。
  4. 發送JWT:一旦JWT被生成,伺服器會將其回傳給使用者,通常是透過HTTP回應的主體或設置在HTTP的Authorization標頭中。
  5. 儲存JWT:客戶端收到JWT後,可以將它存儲在Cookie、LocalStorage或其他合適的地方,以便之後發送請求使用。
  6. 使用JWT訪問受保護資源:當使用者想要訪問一個受到保護的資源(例如API端點)時,他們必須在其請求中帶上JWT,通常是放在HTTP的Authorization標頭中。
  7. 伺服器驗證JWT:當伺服器收到一個請求並附帶JWT時,它會使用公鑰(或相同的私鑰,取決於使用的算法)來驗證Token的完整性和有效性。如果驗證成功,伺服器會處理這個請求;如果失敗,則回傳錯誤。

前端要做的部分

  1. 使用者送出認證資料(Login)
  2. 儲存JWT
  3. 使用JWT訪問受保護資源

使用者送出認證資料(Login)

先前已經開發完登入的功能,當呼叫login api成功後,會收到使用者的資訊。

https://ithelp.ithome.com.tw/upload/images/20231007/20136558LgP6WeO3vb.jpg

儲存JWT

在開發儲存前,先簡單說一下我們要把JWT存放在哪個web storage(cookie、localstorage、sessionstorage)裡。

考慮到安全性會建議存放在Cookie內(因為Cookie可以控制過期時間),詳情請見Token 放 localStorage?sessionStorage?還是 Cookie?
但由於這裡想快速實作出功能,所以先存放至localstorage中。

在把JWT儲存到localstorage裡前,因為回傳的是一個JSON,Web Storage 只能儲存字串,所以要透過JSON.stringfy來轉換。

回傳資料:

{
   "token": 'eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9...', 
   "id": '6512e8482186f21378ab5d34'
}
//Login.js

 const handleSubmit = (event) => {
    if (!formIsValid) return;

    event.preventDefault();

    const userData = {
      email,
      password,
    };

    api
      .post("/auth/login", userData)
      .then((result) => {
        //將回傳的token存放到localstorage
        localStorage.setItem("user", JSON.stringify(result));
      })
      .catch((error) => {
        setErrorMsg('Login failed. Your email or password is incorrect.')
        console.error(error);
      });
  };

當我們完成登入後就能在localstorage裡面看到儲存的使用者資訊了
https://ithelp.ithome.com.tw/upload/images/20231007/20136558qOBvV7nKwQ.jpg

使用JWT訪問受保護資源

當使用者想要訪問一個受到保護的資源(例如API端點)時,他們必須在其請求中帶上JWT,通常是放在HTTP的Authorization標頭中。

我們要在每次呼叫API時在Authorization header都加上JWT,讓後端確認是不是有被授權存取資料。

回到api.js,加上攔截器axios的interceptor

//api.js
import axios from 'axios';

const api = axios.create({
  baseURL: 'http://localhost:5200/api',
});

//因為登入和註冊路由不需要攜帶jwt,所以將他們排除
const EXCLUDED_URLS = ['/auth/login', '/auth/register'];


// 使用request攔截器(interceptor)為每個request 加上 token
api.interceptors.request.use((config) => {

  if (!EXCLUDED_URLS.includes(config.url)) {
    // 從 localStorage 中獲取使用者資訊
    const user = JSON.parse(localStorage.getItem('user'));
    // 使用 && 運算符,檢查 user 和 user.data 是否存在
    const token = user && user.data && user.data.token;
    // 如果 token 存在,
    // 則將他加到到request header的 Authorization 屬性中
    if (token) {
      config.headers['Authorization'] = 'Bearer ' + token;
    }
  }
  // 回傳更新後的配置
  return config;
}, (error) => {
  return Promise.reject(error);
});

export default api;

經過這樣處理後,當我們之後呼叫api時就能自動帶上JWT了。

本次程式碼我放在這github


上一篇
[Day21] 使用Custom Hooks改寫表單驗證、註冊頁開發
下一篇
[Day23] 導覽列開發
系列文
初探全端之旅: 以MERN技術建立個人部落格31
圖片
  直播研討會
圖片
{{ item.channelVendor }} {{ item.webinarstarted }} |
{{ formatDate(item.duration) }}
直播中

尚未有邦友留言

立即登入留言