0Pricing
Vue Academy · บทเรียน

รูปแบบการยืนยันตัวตนที่ปลอดภัย

การจัดเก็บโทเค็น (หน่วยความจำเทียบกับ localStorage เทียบกับคุกกี้ httpOnly) การรีเฟรชแบบเงียบ และการออกจากระบบเมื่อปิดแท็บ

รูปแบบการยืนยันตัวตนที่ปลอดภัย เป็นบทเรียน Vue Academy ฟรีบน CoddyKit นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน คุณสามารถอ่านบทเรียนทั้งหมดด้านล่างฟรี — จากนั้นลองปฏิบัติด้วยตัวคุณเองในเบราว์เซอร์พร้อมตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7 บทเรียนนี้เป็นส่วนหนึ่งของเส้นทางการเรียน Vue Academy และความก้าวหน้าของคุณจะซิงค์ข้ามเว็บและแอป CoddyKit คอร์ส Vue Academy มีบทเรียนทั้งหมด 4 บทเรียน

โทเค็นและตำแหน่งจัดเก็บ

SPA ใช้โทเค็นเพื่อยืนยันตัวตน แต่ตำแหน่งที่จัดเก็บโทเค็นจะเป็นตัวกำหนดความเสี่ยงจาก XSS และ CSRF รูปแบบสมัยใหม่จะแยกโทเค็นเข้าถึงอายุสั้นออกจากโทเค็นรีเฟรชอายุยาว และจัดเก็บแต่ละโทเค็นไว้ต่างกัน

ปัญหาของ localStorage

การจัดเก็บโทเค็นใน localStorage สะดวกแต่มีอันตราย เพราะสคริปต์ใด ๆ ที่ถูกแทรกด้วย XSS สามารถอ่านและส่งโทเค็นออกไปได้ หลีกเลี่ยงการเก็บข้อมูลรับรองไว้ที่นั่น

// AVOID
localStorage.setItem("token", accessToken);

โทเค็นเข้าถึงในหน่วยความจำ

เก็บโทเค็นเข้าถึงไว้ในตัวแปร JavaScript หรือรีแอกทีฟรีฟ โทเค็นจะหายไปเมื่อโหลดใหม่ ดังนั้น XSS ที่ทำงานสำเร็จจะมีช่วงเวลาโจมตีสั้นลงมาก และจะไม่มีข้อมูลใดคงอยู่บนดิสก์

import { ref } from "vue";

export const accessToken = ref(null);

โทเค็นรีเฟรชในคุกกี้ httpOnly

โทเค็นรีเฟรชจะอยู่ในคุกกี้ HttpOnly, Secure, SameSite JavaScript ไม่สามารถอ่านคุกกี้นี้ได้ ดังนั้น XSS จึงขโมยไม่ได้ และเบราว์เซอร์จะส่งคุกกี้นี้เฉพาะไปยังจุดปลายทางการยืนยันตัวตนของคุณ

Set-Cookie: refresh=...; HttpOnly; Secure; SameSite=Strict; Path=/auth

การแนบโทเค็นเข้าถึง

ตัวสกัดกั้นคำขอของ Axios จะเพิ่มโทเค็นเข้าถึงในหน่วยความจำลงในส่วนหัวการอนุญาตของทุกคำเรียก

api.interceptors.request.use((config) => {
  if (accessToken.value) {
    config.headers.Authorization = "Bearer " + accessToken.value;
  }
  return config;
});

การตรวจจับการหมดอายุ: 401

เมื่อโทเค็นเข้าถึงหมดอายุ เซิร์ฟเวอร์จะตอบกลับด้วย 401 Unauthorized ตัวสกัดกั้นการตอบกลับจะตรวจจับเหตุการณ์นี้เพื่อเรียกการรีเฟรช

api.interceptors.response.use(
  (res) => res,
  async (error) => {
    if (error.response?.status === 401) {
      // attempt refresh
    }
    return Promise.reject(error);
  }
);

การรีเฟรชโทเค็น

เมื่อได้รับ 401 ให้เรียกจุดปลายทางสำหรับรีเฟรช เบราว์เซอร์จะส่งคุกกี้รีเฟรช httpOnly ให้อัตโนมัติ (withCredentials) และเซิร์ฟเวอร์จะส่งโทเค็นเข้าถึงใหม่กลับมา

const { data } = await axios.post("/auth/refresh", null, {
  withCredentials: true
});
accessToken.value = data.accessToken;

การลองส่งคำขอเดิมอีกครั้ง

หลังรีเฟรช ให้ส่งคำขอเดิมที่ล้มเหลวซ้ำด้วยโทเค็นใหม่ เพื่อไม่ให้ผู้ใช้สังเกตเห็น

async (error) => {
  const original = error.config;
  if (error.response?.status === 401 && !original._retry) {
    original._retry = true;
    const { data } = await axios.post("/auth/refresh", null, { withCredentials: true });
    accessToken.value = data.accessToken;
    original.headers.Authorization = "Bearer " + data.accessToken;
    return api(original);
  }
  return Promise.reject(error);
}

ป้องกันการรีเฟรชถล่มพร้อมกัน

หากคำขอจำนวนมากได้รับ 401 พร้อมกัน ให้เข้าคิวไว้เบื้องหลังการรีเฟรชเดียวที่กำลังทำงานอยู่ เพื่อไม่ให้เรียกปลายทางรีเฟรชซ้ำ ๆ

let refreshing = null;
function refresh() {
  if (!refreshing) {
    refreshing = axios.post("/auth/refresh", null, { withCredentials: true })
      .finally(() => { refreshing = null; });
  }
  return refreshing;
}

การออกจากระบบ

เมื่อออกจากระบบ ให้ล้างโทเค็นในหน่วยความจำและเรียกปลายทางที่ล้างคุกกี้รีเฟรชจากฝั่งเซิร์ฟเวอร์

async function logout() {
  accessToken.value = null;
  await axios.post("/auth/logout", null, { withCredentials: true });
}

ผสานกับการป้องกัน CSRF

เนื่องจากคุกกี้รีเฟรชถูกส่งโดยอัตโนมัติ ให้ป้องกันปลายทางดังกล่าวด้วย SameSite และโทเค็น CSRF เช่นเดียวกับเส้นทางอื่น ๆ ที่ยืนยันตัวตนด้วยคุกกี้

ตรวจสอบอย่างรวดเร็ว

ควรเก็บ access token และ refresh token ไว้ที่ใดบ้าง

สรุป

เก็บ access token ไว้ในรีฟที่อยู่ในหน่วยความจำ (ห้ามใช้ localStorage) และเก็บ refresh token ไว้ในคุกกี้ HttpOnly ตัวดักจับคำขอจะเพิ่มโทเค็นแบบผู้ถือ ส่วนตัวดักจับการตอบกลับจะตรวจจับ 401 เรียกปลายทางรีเฟรช อัปเดตโทเค็น และลองส่งคำขอเดิมอีกครั้ง โดยรวมการรีเฟรชที่เกิดพร้อมกันให้เหลือครั้งเดียวและใช้ควบคู่กับการป้องกัน CSRF

คำถามที่พบบ่อย

บทเรียน “รูปแบบการยืนยันตัวตนที่ปลอดภัย” ฟรีหรือไม่

ใช่ — ข้อความเต็มของ “รูปแบบการยืนยันตัวตนที่ปลอดภัย” ฟรีให้อ่านที่นี่บนเว็บ เพื่อปฏิบัติแบบโต้ตอบ (ตัวแก้ไขโค้ดในตัวและติวเตอร์ AI ตลอด 24/7) และปลดล็อคส่วนที่เหลือของคอร์ส Vue Academy ให้อัปเกรดเป็น CoddyKit PRO คอร์ส Vue Academy มีบทเรียนทั้งหมด 4 บทเรียน

คุณจะเรียนรู้อะไรในบทเรียน “รูปแบบการยืนยันตัวตนที่ปลอดภัย”

การจัดเก็บโทเค็น (หน่วยความจำเทียบกับ localStorage เทียบกับคุกกี้ httpOnly) การรีเฟรชแบบเงียบ และการออกจากระบบเมื่อปิดแท็บ คุณปฏิบัติ Vue Academy ด้วยโค้ดที่ใช้งานได้จริงที่คุณเรียกใช้โดยตรงในเบราว์เซอร์ และติวเตอร์ AI ตลอด 24/7 ตอบคำถามของคุณขณะที่คุณไปผ่านบทเรียน

คุณต้องมีประสบการณ์ก่อนที่จะเริ่มเรียน Vue Academy หรือไม่

ไม่จำเป็นต้องมีประสบการณ์มาก่อน Vue Academy บน CoddyKit ออกแบบมาสำหรับผู้เริ่มต้นไปจนถึงผู้เรียนขั้นสูง คุณสามารถเริ่มต้นที่นี่หรือเริ่มจากตัวแรกและเรียนด้วยความเร็วของคุณเอง นี่คือบทเรียนที่ 4 จากทั้งหมด 4 บทเรียน

บทเรียน “รูปแบบการยืนยันตัวตนที่ปลอดภัย” ใช้เวลานานแค่ไหน

บทเรียน CoddyKit ส่วนใหญ่ใช้เวลาประมาณ 5–10 นาที แต่ละบทเรียนจึงสั้นและเป็นแบบโต้ตอบ คุณสามารถก้าวหน้าอย่างต่อเนื่องและกลับมาเรียนต่อจากตรงที่เพิ่งหยุดบนเว็บและแอปได้เลย

ฉันเขียนและรันโค้ดในบทเรียน Vue Academy นี้ได้ไหม

ได้ บทเรียน Vue Academy ทุกบทมีตัวแก้ไขโค้ดในตัว คุณจึงเขียนและรันโค้ดจริงได้เลยในเบราว์เซอร์ และได้รับข้อเสนอแนะจาก AI ในทันที — ไม่ต้องติดตั้งในเครื่องของคุณ

บทเรียนทั้งหมดในหลักสูตรนี้

  1. การป้องกัน XSS ใน Vue
  2. Content Security Policy (CSP) กับ Vue
  3. การป้องกัน CSRF ใน SPA ของ Vue
  4. รูปแบบการยืนยันตัวตนที่ปลอดภัย
← กลับไปที่ Vue Academy