แสดงบทความที่มีป้ายกำกับ JWT แสดงบทความทั้งหมด
แสดงบทความที่มีป้ายกำกับ JWT แสดงบทความทั้งหมด

วันเสาร์ที่ 22 มีนาคม พ.ศ. 2568

การทำ Role-based Authentication ใน Next.js – แยกสิทธิ์ Admin, User, และ Guest

อยากให้เว็บ Next.js ของเรามีระบบแบ่งสิทธิ์การเข้าถึง (RBAC – Role-Based Access Control) ไหม?
เช่น Admin ดูข้อมูลทั้งหมดได้, User ใช้งานปกติ, Guest เข้าได้เฉพาะบางหน้า

🎯 วันนี้เราจะมาทำ Role-based Authentication ใน Next.js

✅ รองรับ JWT Authentication
✅ ใช้ Middleware เช็ก Role ก่อนเข้าหน้าเว็บ
✅ มีตัวอย่าง API แยกสิทธิ์ Admin และ User

🎯 Role-based Authentication คืออะไร?

RBAC (Role-Based Access Control) คือ การกำหนดสิทธิ์ของผู้ใช้ตามบทบาท (Role) เช่น

  • Admin 🛡️ – แก้ไขข้อมูลทุกอย่างได้
  • User 👤 – ใช้งานฟีเจอร์ปกติ
  • Guest 👥 – ดูข้อมูลบางอย่างได้

💡 เราจะใช้ JWT (JSON Web Token) ในการจัดการ Authentication & Role


🚀 1. ติดตั้งโปรเจกต์ Next.js และไลบรารี

เริ่มต้นด้วยการสร้างโปรเจกต์ Next.js และติดตั้งไลบรารีที่จำเป็น

npx create-next-app role-based-auth
cd role-based-auth
npm install jsonwebtoken bcryptjs cookie

  • jsonwebtoken – ใช้สำหรับสร้างและตรวจสอบ JWT
  • bcryptjs – ใช้เข้ารหัสรหัสผ่าน
  • cookie – ใช้จัดการ Token ผ่าน Cookie


🔐 2. สร้างระบบ Authentication (JWT)

📌 สร้าง API Register (สมัครสมาชิก)

📌 ไฟล์: pages/api/auth/register.js

import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";

const users = []; // จำลองฐานข้อมูลใน Memory

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { email, password, role } = req.body;
  if (!email || !password || !role) return res.status(400).json({ error: "Missing fields" });

  const hashedPassword = await bcrypt.hash(password, 10);
  const newUser = { email, password: hashedPassword, role };
  users.push(newUser);

  res.json({ message: "User registered", user: { email, role } });
}

✅ สมัครสมาชิก พร้อมเก็บ role (เช่น admin หรือ user)

📌 สร้าง API Login (เข้าสู่ระบบ)

📌 ไฟล์: pages/api/auth/login.js

import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";
import { serialize } from "cookie";

const users = []; // ใช้ฐานข้อมูลจริงในโปรเจกต์จริง

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { email, password } = req.body;
  const user = users.find((u) => u.email === email);
  if (!user) return res.status(401).json({ error: "User not found" });

  const isMatch = await bcrypt.compare(password, user.password);
  if (!isMatch) return res.status(401).json({ error: "Invalid password" });

  const token = jwt.sign({ email: user.email, role: user.role }, "SECRET_KEY", { expiresIn: "1h" });

  res.setHeader("Set-Cookie", serialize("auth_token", token, { httpOnly: true, path: "/" }));
  res.json({ message: "Login successful", token });
}

✅ ตรวจสอบรหัสผ่าน และสร้าง JWT Token
✅ เก็บ Token ใน Cookie เพื่อใช้ใน Middleware

🚦 3. สร้าง Middleware เช็ก Role

📌 ไฟล์: middleware/auth.js

import jwt from "jsonwebtoken";
import { parse } from "cookie";

export function withAuth(handler, allowedRoles) {
  return async (req, res) => {
    const cookies = parse(req.headers.cookie || "");
    const token = cookies.auth_token;

    if (!token) return res.status(401).json({ error: "Not authenticated" });

    try {
      const decoded = jwt.verify(token, "SECRET_KEY");
      if (!allowedRoles.includes(decoded.role)) {
        return res.status(403).json({ error: "Access Denied" });
      }

      req.user = decoded; // ส่งข้อมูลผู้ใช้ไปยัง API
      return handler(req, res);
    } catch (error) {
      return res.status(401).json({ error: "Invalid Token" });
    }
  };
}

✅ เช็กว่า JWT ถูกต้อง & Role ตรงกับสิทธิ์ที่กำหนด

🔥 4. สร้าง API แยกสิทธิ์

📌 API เฉพาะ Admin

📌 ไฟล์: pages/api/admin.js

import { withAuth } from "../../middleware/auth";

export default withAuth((req, res) => {
  res.json({ message: "Welcome Admin!", user: req.user });
}, ["admin"]);

✅ เฉพาะ Admin เท่านั้นที่เรียก API นี้ได้

📌 API สำหรับ User & Admin

📌 ไฟล์: pages/api/user.js

import { withAuth } from "../../middleware/auth";

export default withAuth((req, res) => {
  res.json({ message: `Welcome ${req.user.role}!`, user: req.user });
}, ["user", "admin"]);

✅ ทั้ง User & Admin ใช้งานได้


🎨 5. สร้าง UI หน้าเว็บ

📌 ไฟล์: pages/index.js

import { useState } from "react";

export default function Home() {
  const [message, setMessage] = useState("");

  const checkAdmin = async () => {
    const res = await fetch("/api/admin");
    const data = await res.json();
    setMessage(data.message || data.error);
  };

  const checkUser = async () => {
    const res = await fetch("/api/user");
    const data = await res.json();
    setMessage(data.message || data.error);
  };

  return (
    <div>
      <h1>Role-based Authentication</h1>
      <button onClick={checkAdmin}>Check Admin</button>
      <button onClick={checkUser}>Check User</button>
      <p>{message}</p>
    </div>
  );
}

✅ ทดสอบ กดปุ่ม Check Admin หรือ Check User เพื่อดูสิทธิ์



🚀 6. ทดสอบระบบ

  1. รันเซิร์ฟเวอร์ npm run dev
  2. สมัครสมาชิก → /api/auth/register
  3. ล็อกอิน → /api/auth/login
  4. ลองเรียก /api/admin และ /api/user ดูว่า Role ตรงไหม


🎯 สรุป

✅ ใช้ JWT และ Middleware จัดการ Role
✅ แยกสิทธิ์ Admin, User, Guest
✅ ใช้ API แยก Role เพื่อควบคุมสิทธิ์การเข้าถึง

💡 พร้อมใช้กับเว็บจริง! แค่เพิ่ม Database และ UI สวยๆ เท่านั้น! 🚀

วันพฤหัสบดีที่ 20 มีนาคม พ.ศ. 2568

การจัดการ Session และ Cookie ใน Next.js แบบเข้าใจง่าย!

Session และ Cookie เป็นสิ่งที่ขาดไม่ได้ในระบบเว็บแอป Next.js ไม่ว่าจะเป็นการ จัดการผู้ใช้ (Authentication), จดจำค่าต่างๆ หรือ รักษาความปลอดภัยของแอป

📌 บทความนี้จะอธิบายว่า Session & Cookie คืออะไร และ ใช้งานใน Next.js ยังไง พร้อมตัวอย่างโค้ดแบบจับมือทำ! 🚀

🎯 Session และ Cookie คืออะไร?

🍪 Cookie

Cookie เป็นข้อมูลเล็กๆ ที่ browser เก็บไว้ในเครื่องของผู้ใช้ โดยส่งไปพร้อมกับทุกๆ request เพื่อให้เซิร์ฟเวอร์จำผู้ใช้ได้

🔹 ใช้สำหรับ จดจำสถานะของผู้ใช้ (เช่นล็อกอินอยู่หรือเปล่า?)
🔹 สามารถตั้งค่า หมดอายุ (Expire) ได้
🔹 มีการจำกัดขนาดข้อมูล (โดยทั่วไปไม่เกิน 4KB)

🔐 Session

Session คือการเก็บข้อมูลของผู้ใช้ ฝั่งเซิร์ฟเวอร์ และอ้างอิงด้วย Session ID ที่เก็บไว้ใน Cookie

🔹 ปลอดภัยกว่าการเก็บข้อมูลใน Cookie เพราะข้อมูลไม่ได้ถูกเก็บไว้ที่ฝั่งผู้ใช้
🔹 ต้องใช้ Session Storage เช่น Redis, Database หรือ Memory
🔹 มีอายุการใช้งานตามที่กำหนด (เช่น 30 นาที)

💡 โดยทั่วไป Session & Cookie ใช้งานร่วมกัน คือ เก็บ Session ID ไว้ใน Cookie เพื่อให้เซิร์ฟเวอร์ดึงข้อมูลผู้ใช้มาใช้ได้


🚀 วิธีใช้งาน Cookie ใน Next.js

📌 ติดตั้งไลบรารีจัดการ Cookie

npm install cookie


🔹 สร้าง API ที่ใช้ Cookie ใน Next.js

📌 โค้ด: pages/api/auth/set-cookie.js

import { serialize } from "cookie";

export default function handler(req, res) {
  const token = "my_secure_token"; // จำลอง token

  res.setHeader("Set-Cookie", serialize("auth_token", token, {
    httpOnly: true, // ป้องกันการเข้าถึงจาก JavaScript
    secure: process.env.NODE_ENV === "production", // ใช้ https ในโหมด production
    maxAge: 60 * 60 * 24, // 1 วัน
    sameSite: "strict",
    path: "/",
  }));

  res.json({ message: "Cookie set!" });
}

✅ API นี้จะสร้าง auth_token แล้วฝังไว้ใน Cookie
✅ ตั้งค่า httpOnly เพื่อให้ปลอดภัยจาก XSS
✅ หมดอายุใน 1 วัน

🔹 อ่านค่า Cookie

📌 โค้ด: pages/api/auth/get-cookie.js

import { parse } from "cookie";

export default function handler(req, res) {
  const cookies = parse(req.headers.cookie || "");
  res.json({ token: cookies.auth_token || "No token found" });
}

✅ API นี้จะอ่านค่า auth_token จาก Cookie

🔹 ลบ Cookie (Logout)

📌 โค้ด: pages/api/auth/logout.js

import { serialize } from "cookie";

export default function handler(req, res) {
  res.setHeader("Set-Cookie", serialize("auth_token", "", {
    httpOnly: true,
    secure: process.env.NODE_ENV === "production",
    expires: new Date(0), // ลบ Cookie
    path: "/",
  }));

  res.json({ message: "Logged out!" });
}

✅ API นี้จะลบ Cookie โดยตั้งค่า expire เป็น 0


🚀 วิธีใช้งาน Session ใน Next.js

📌 ติดตั้งไลบรารี Session

npm install next-session

next-session เป็นไลบรารีที่ช่วยจัดการ Session ใน Next.js API Routes ได้ง่าย

🔹 ตั้งค่า Session Middleware

📌 โค้ด: lib/session.js

import { withIronSessionApiRoute } from "iron-session/next";

export function withSession(handler) {
  return withIronSessionApiRoute(handler, {
    cookieName: "session_cookie",
    password: "complex_password_123", // ควรใช้ env variable
    cookieOptions: {
      secure: process.env.NODE_ENV === "production",
    },
  });
}

✅ ใช้ iron-session เก็บ Session อย่างปลอดภัย
✅ ตั้งค่า session_cookie เป็นที่เก็บ Session

🔹 สร้าง API ที่ใช้ Session

📌 โค้ด: pages/api/auth/login.js

import { withSession } from "../../lib/session";

export default withSession(async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  req.session.user = { id: 1, username: "admin" };
  await req.session.save();

  res.json({ message: "Login successful", user: req.session.user });
});

✅ เมื่อล็อกอินสำเร็จ จะเก็บข้อมูลผู้ใช้ใน Session

🔹 ดึงข้อมูลจาก Session

📌 โค้ด: pages/api/auth/me.js

import { withSession } from "../../lib/session";

export default withSession(async function handler(req, res) {
  if (!req.session.user) {
    return res.status(401).json({ error: "Not authenticated" });
  }

  res.json({ user: req.session.user });
});

✅ API นี้จะเช็กว่า มี Session ไหม? ถ้ามีแสดงข้อมูลผู้ใช้

🔹 ลบ Session (Logout)

📌 โค้ด: pages/api/auth/logout.js

import { withSession } from "../../lib/session";

export default withSession(async function handler(req, res) {
  req.session.destroy();
  res.json({ message: "Logged out!" });
});

✅ API นี้จะ ลบ Session แล้วทำให้ผู้ใช้ต้องล็อกอินใหม่

🎨 สร้างหน้า UI สำหรับ Login

📌 โค้ด: pages/index.js

import { useState } from "react";

export default function Home() {
  const [message, setMessage] = useState("");

  const login = async () => {
    const res = await fetch("/api/auth/login", { method: "POST" });
    const data = await res.json();
    setMessage(data.message);
  };

  const checkSession = async () => {
    const res = await fetch("/api/auth/me");
    const data = await res.json();
    setMessage(data.user ? `Logged in as ${data.user.username}` : "Not authenticated");
  };

  return (
    <div>
      <h1>Session & Cookie in Next.js</h1>
      <button onClick={login}>Login</button>
      <button onClick={checkSession}>Check Session</button>
      <p>{message}</p>
    </div>
  );
}

✅ UI นี้จะ Login แล้วเช็กว่า Session ยังอยู่ไหม?


🚀 ทดสอบระบบ

  1. รันเซิร์ฟเวอร์ npm run dev
  2. เปิด http://localhost:3000
  3. กด Login แล้วดูว่ามี Session หรือไม่


🎯 สรุป

✅ Cookie – ใช้เก็บข้อมูลเล็กๆ ฝั่ง client
✅ Session – ใช้เก็บข้อมูลฝั่งเซิร์ฟเวอร์
✅ Next.js API Routes รองรับทั้ง Cookie & Session
✅ ใช้ iron-session ทำให้การจัดการ Session ง่ายขึ้น

วันพุธที่ 19 มีนาคม พ.ศ. 2568

การสร้างระบบสมาชิก (Sign-up & Login) ใน Next.js แบบเข้าใจง่าย!

อยากทำระบบ สมัครสมาชิก (Sign-up) + ล็อกอิน (Login) ใน Next.js ใช่ไหม? 🤔 ไม่ต้องห่วง บทความนี้จะพาไปทำแบบ step-by-step ตั้งแต่สร้างบัญชี, เข้ารหัสรหัสผ่าน, จัดการ JWT Token, ยันป้องกัน API รับรองว่าอ่านจบแล้วทำเป็นแน่นอน!

🎯 แผนที่ที่เราจะทำ

✅ สมัครสมาชิก (Sign-up)
✅ เข้าสู่ระบบ (Login) พร้อมสร้าง JWT Token
✅ ป้องกัน API ด้วย Token
✅ แสดงข้อมูลผู้ใช้ที่ล็อกอินอยู่

💡 ใช้แค่ Next.js API Routes, bcrypt, และ JSON Web Token (JWT) ไม่ต้องมีเซิร์ฟเวอร์เพิ่ม!


🛠️ ติดตั้ง Next.js และไลบรารีที่จำเป็น

ก่อนอื่นต้องมีโปรเจกต์ Next.js ถ้ายังไม่มีให้สร้างเลย

npx create-next-app@latest my-auth-app
cd my-auth-app
npm install bcryptjs jsonwebtoken

👉 bcryptjs – ใช้เข้ารหัสรหัสผ่าน
👉 jsonwebtoken – ใช้สร้างและตรวจสอบ JWT Token


🔐 สร้าง API สำหรับ สมัครสมาชิก (Sign-up)

📌 โค้ด: pages/api/auth/signup.js

import bcrypt from "bcryptjs";

let users = []; // จำลองเป็น Database (จริงๆ ควรใช้ MongoDB หรือ PostgreSQL)

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { username, password } = req.body;

  if (users.find((u) => u.username === username)) {
    return res.status(400).json({ error: "Username already exists" });
  }

  const hashedPassword = await bcrypt.hash(password, 10);
  const newUser = { id: Date.now(), username, password: hashedPassword };

  users.push(newUser);
  res.json({ message: "User registered", user: { id: newUser.id, username: newUser.username } });
}

🔹 เช็กว่าชื่อผู้ใช้ซ้ำหรือไม่
🔹 เข้ารหัสรหัสผ่านก่อนบันทึก


🔑 สร้าง API สำหรับ เข้าสู่ระบบ (Login)

📌 โค้ด: pages/api/auth/login.js

import bcrypt from "bcryptjs";
import jwt from "jsonwebtoken";

let users = []; // จำลอง Database (ใช้ร่วมกับ signup.js)

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { username, password } = req.body;
  const user = users.find((u) => u.username === username);

  if (!user || !(await bcrypt.compare(password, user.password))) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  const token = jwt.sign({ userId: user.id, username: user.username }, "SECRET_KEY", { expiresIn: "1h" });

  res.json({ message: "Login successful", token });
}

🔐 ถ้าล็อกอินสำเร็จ จะสร้าง JWT Token และส่งกลับไปให้ client


🛡️ สร้าง API ที่ต้องใช้ Token ในการเข้าถึง

📌 โค้ด: pages/api/auth/me.js

import jwt from "jsonwebtoken";

export default function handler(req, res) {
  const { authorization } = req.headers;
 
  if (!authorization) return res.status(401).json({ error: "No token provided" });

  try {
    const token = authorization.split(" ")[1];
    const decoded = jwt.verify(token, "SECRET_KEY");
    res.json({ message: "Authenticated", user: decoded });
  } catch (err) {
    res.status(401).json({ error: "Invalid token" });
  }
}

🔒 API นี้ต้องใช้ JWT Token ใน Authorization header เพื่อเข้าถึง


🎨 สร้างหน้า UI สำหรับ สมัครสมาชิก + ล็อกอิน

📌 โค้ด: pages/index.js

import { useState } from "react";

export default function Home() {
  const [username, setUsername] = useState("");
  const [password, setPassword] = useState("");
  const [token, setToken] = useState(null);
  const [message, setMessage] = useState("");

  const signup = async () => {
    const res = await fetch("/api/auth/signup", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    });

    const data = await res.json();
    setMessage(data.message);
  };

  const login = async () => {
    const res = await fetch("/api/auth/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username, password }),
    });

    const data = await res.json();
    if (data.token) {
      setToken(data.token);
      setMessage("Login successful!");
    } else {
      setMessage("Login failed");
    }
  };

  const getUserData = async () => {
    const res = await fetch("/api/auth/me", {
      headers: { Authorization: `Bearer ${token}` },
    });

    const data = await res.json();
    setMessage(data.message || "Access denied");
  };

  return (
    <div>
      <h1>Sign-up & Login System</h1>
      <input type="text" placeholder="Username" onChange={(e) => setUsername(e.target.value)} />
      <input type="password" placeholder="Password" onChange={(e) => setPassword(e.target.value)} />
      <button onClick={signup}>Sign Up</button>
      <button onClick={login}>Login</button>
      <button onClick={getUserData} disabled={!token}>Get User Data</button>
      <p>{message}</p>
    </div>
  );
}

💡 อธิบายโค้ด:

✅ กรอกชื่อผู้ใช้ + รหัสผ่าน แล้วกด Sign Up เพื่อสมัคร
✅ กด Login ถ้าสำเร็จจะได้ JWT Token
✅ กด Get User Data เพื่อเรียก API ที่ป้องกันไว้


🚀 ทดสอบระบบ

  1. รันเซิร์ฟเวอร์ npm run dev
  2. เปิด http://localhost:3000
  3. ลอง Sign-up > Login > กด Get User Data

ถ้า JWT Token ถูกต้อง API จะให้เข้าถึงข้อมูลได้! 🎉


🎯 สรุป

✅ Sign-up พร้อมเข้ารหัสรหัสผ่าน
✅ Login แล้วสร้าง JWT Token
✅ ป้องกัน API ด้วย JWT
✅ ใช้ Next.js API Routes ทำระบบ Authentication แบบ stateless

🚀 พร้อมใช้ในโปรเจกต์จริง เพิ่ม Database และ refresh token ได้เลย!

วันอังคารที่ 18 มีนาคม พ.ศ. 2568

การใช้ JWT Authentication ใน Next.js แบบง่ายแต่โหด

ถ้าคุณกำลังทำเว็บแอปด้วย Next.js และอยากได้ระบบล็อกอินที่ปลอดภัยแต่ไม่ยุ่งยาก JWT Authentication คือคำตอบ! 😎

JWT (JSON Web Token) เป็นมาตรฐานสำหรับการส่งข้อมูลแบบ secure ระหว่าง client และ server โดยไม่ต้องใช้ session บนเซิร์ฟเวอร์ให้ยุ่งยาก ซึ่งเหมาะกับแอปที่ต้องการ stateless authentication เช่น Next.js API Routes หรือ Serverless Functions

บทความนี้จะพาไปดูวิธีใช้งาน JWT Authentication ใน Next.js ตั้งแต่เริ่มต้น ยันการป้องกัน API ให้ปลอดภัย 💪

🎯 JWT คืออะไร?

JWT (JSON Web Token) เป็นโทเค็นเข้ารหัสที่ใช้แทน session ในการตรวจสอบตัวตน (Authentication) ของผู้ใช้ โดยมันจะถูกฝังข้อมูล เช่น user ID, role, email ไว้ข้างใน และสามารถใช้ยืนยันตัวตนในทุกๆ Request ได้

JWT มี 3 ส่วนหลักๆ คือ

  • Header – บอกว่าใช้การเข้ารหัสแบบไหน
  • Payload – ข้อมูลของผู้ใช้ เช่น ID, ชื่อ, อีเมล
  • Signature – ใช้สำหรับยืนยันว่าโทเค็นถูกต้อง


ตัวอย่าง JWT แบบดิบๆ 👇

eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJ1c2VySWQiOjEsImlhdCI6MTYxNjIzOTAyMn0.PF-0Ff_q2Gsk2tKAlDhEwMzMfJvc_ZjZbnF0qU4aMSk

ลองเอาไป Decode ได้ที่ jwt.io 😃



🛠️ ติดตั้ง Next.js และ JWT

ก่อนอื่นต้องมีโปรเจกต์ Next.js ก่อน ถ้ายังไม่มี ก็กดสร้างเลย

npx create-next-app@latest jwt-auth-app
cd jwt-auth-app
npm install jsonwebtoken bcryptjs

👉 jsonwebtoken – ใช้สำหรับสร้างและตรวจสอบ JWT
👉 bcryptjs – ใช้เข้ารหัสรหัสผ่าน


🔐 สร้าง API สำหรับ JWT Authentication

1️⃣ สร้าง API สำหรับ ล็อกอิน และสร้าง JWT

ไปที่ pages/api/auth/login.js แล้วใส่โค้ดนี้

import jwt from "jsonwebtoken";
import bcrypt from "bcryptjs";

// ข้อมูลผู้ใช้ตัวอย่าง (จริงๆ ควรใช้ DB)
const users = [{ id: 1, username: "admin", password: "$2a$10$KIX/b0WwQJHsc/mxL6RoGuLbqVZXuWEC1Q2tB3MTzK8K4NrdH5r3W" }]; // รหัสผ่าน: 123456

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { username, password } = req.body;
  const user = users.find((u) => u.username === username);

  if (!user || !(await bcrypt.compare(password, user.password))) {
    return res.status(401).json({ error: "Invalid credentials" });
  }

  const token = jwt.sign({ userId: user.id, username: user.username }, "SECRET_KEY", { expiresIn: "1h" });

  res.json({ token });
}

🔹 เราใช้ bcryptjs เพื่อตรวจสอบรหัสผ่าน
🔹 ถ้าล็อกอินสำเร็จ จะสร้าง JWT Token แล้วส่งกลับไปให้ client

2️⃣ สร้าง API สำหรับ ป้องกัน API ด้วย JWT

สร้างไฟล์ pages/api/protected.js

import jwt from "jsonwebtoken";

export default function handler(req, res) {
  const { authorization } = req.headers;
 
  if (!authorization) return res.status(401).json({ error: "No token provided" });

  try {
    const token = authorization.split(" ")[1];
    const decoded = jwt.verify(token, "SECRET_KEY");
    res.json({ message: "Protected data", user: decoded });
  } catch (err) {
    res.status(401).json({ error: "Invalid token" });
  }
}

🔒 API นี้จะตรวจสอบว่า

✅ มี JWT Token ใน Authorization header ไหม
✅ ถอดรหัสแล้วถูกต้องหรือไม่

3️⃣ สร้าง API สำหรับ สมัครสมาชิก

สร้างไฟล์ pages/api/auth/register.js

import bcrypt from "bcryptjs";

export default async function handler(req, res) {
  if (req.method !== "POST") return res.status(405).json({ error: "Method Not Allowed" });

  const { username, password } = req.body;
  const hashedPassword = await bcrypt.hash(password, 10);

  // จำลองการบันทึกลง DB
  const newUser = { id: Date.now(), username, password: hashedPassword };

  res.json({ message: "User registered", user: newUser });
}

🔹 ใช้ bcryptjs เพื่อเข้ารหัสรหัสผ่านก่อนบันทึก
🔹 จำลองว่าเราเก็บข้อมูลผู้ใช้ใน DB


🎨 สร้าง UI สำหรับล็อกอิน

เปิดไฟล์ pages/index.js แล้วใส่โค้ดนี้

import { useState } from "react";

export default function Home() {
  const [token, setToken] = useState(null);
  const [message, setMessage] = useState("");

  const login = async () => {
    const res = await fetch("/api/auth/login", {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify({ username: "admin", password: "123456" }),
    });

    const data = await res.json();
    if (data.token) {
      setToken(data.token);
      setMessage("Login successful!");
    } else {
      setMessage("Login failed");
    }
  };

  const accessProtected = async () => {
    const res = await fetch("/api/protected", {
      headers: { Authorization: `Bearer ${token}` },
    });

    const data = await res.json();
    setMessage(data.message || "Access denied");
  };

  return (
    <div>
      <h1>JWT Authentication in Next.js</h1>
      <button onClick={login}>Login</button>
      <button onClick={accessProtected} disabled={!token}>Access Protected API</button>
      <p>{message}</p>
    </div>
  );
}

💡 อธิบายโค้ด:

  • ปุ่ม Login จะส่ง Username และ Password ไปที่ API
  • ถ้าล็อกอินสำเร็จจะได้ JWT Token มาเก็บไว้
  • ปุ่ม Access Protected API จะส่ง JWT Token ไปที่ API ที่ต้องการป้องกัน


🚀 ทดสอบระบบ JWT Authentication

  1.     รันเซิร์ฟเวอร์ npm run dev
  2.     เปิด http://localhost:3000
  3.     กดปุ่ม "Login"
  4.     กดปุ่ม "Access Protected API" เพื่อดูว่ามีสิทธิ์เข้าถึงหรือไม่


🎯 สรุป

✅ JWT Authentication ทำให้ระบบล็อกอินเป็นแบบ stateless และปลอดภัย
✅ ไม่ต้องใช้ session storage บนเซิร์ฟเวอร์
✅ ใช้งานง่ายกับ Next.js API Routes

แค่นี้ก็ได้ระบบล็อกอินเทพๆ ไปใช้ในแอป Next.js แล้ว! 🔥

วันเสาร์ที่ 15 มีนาคม พ.ศ. 2568

การจัดการ Authentication กับฐานข้อมูล ใน Next.js

การสร้างระบบ Authentication หรือการยืนยันตัวตนในแอปพลิเคชันเว็บคือขั้นตอนที่สำคัญที่สุดขั้นตอนหนึ่งในการพัฒนาเว็บแอป เพราะไม่ว่าระบบนั้นจะเป็นระบบที่ให้ผู้ใช้ทำการสมัครสมาชิก เข้าสู่ระบบ หรือแม้แต่การเข้าถึงข้อมูลส่วนตัว การมีระบบที่สามารถจัดการ Authentication ได้ดีจะช่วยให้การใช้งานระบบมีความปลอดภัย และมั่นใจได้ว่า ผู้ใช้ที่เข้ามาจะต้องมีสิทธิ์ ในการใช้งานตามที่กำหนด

สำหรับ Next.js ซึ่งเป็น framework ที่พัฒนาโดย React, การจัดการ Authentication ถือเป็นส่วนที่สำคัญ โดยเฉพาะอย่างยิ่งเมื่อเราต้องทำการจัดการกับฐานข้อมูล เช่น MySQL, MongoDB หรือ PostgreSQL ซึ่งในบทความนี้เราจะพูดถึงวิธีการจัดการ Authentication บน Next.js ด้วยการเชื่อมต่อกับฐานข้อมูล โดยใช้เครื่องมือที่นิยมอย่าง bcrypt และ JWT (JSON Web Token) เพื่อให้ผู้ใช้สามารถลงทะเบียน เข้าสู่ระบบ และสามารถเข้าถึงข้อมูลที่มีการรักษาความปลอดภัยได้

เริ่มต้นสร้างโปรเจคใน Next.js

ก่อนที่เราจะเริ่มต้นการสร้างระบบ Authentication ด้วย Next.js เราต้องสร้างโปรเจค Next.js ขึ้นมาก่อน และติดตั้งแพ็กเกจที่จำเป็นบางตัว ซึ่งในที่นี้เราจะใช้ bcryptjs สำหรับการเข้ารหัสรหัสผ่าน, jsonwebtoken (JWT) สำหรับการสร้างและจัดการ Token, และ Prisma หรือ Sequelize สำหรับการจัดการกับฐานข้อมูล

1. สร้างโปรเจค Next.js

การสร้างโปรเจค Next.js เป็นขั้นตอนที่ง่ายมาก เพียงแค่ใช้คำสั่งต่อไปนี้ในเทอร์มินัล:

npx create-next-app@latest my-auth-app
cd my-auth-app

เมื่อสร้างโปรเจคเสร็จแล้ว ให้ทำการติดตั้ง dependencies ที่จำเป็น:

npm install bcryptjs jsonwebtoken prisma @prisma/client

2. ตั้งค่า Prisma สำหรับฐานข้อมูล


ถ้าคุณเลือกใช้ Prisma ในการจัดการฐานข้อมูลคุณต้องทำการตั้งค่า Prisma เพื่อเชื่อมต่อกับฐานข้อมูลที่คุณใช้ เช่น MySQL, PostgreSQL, หรือ SQLite ต่อไปนี้คือการตั้งค่าพื้นฐานสำหรับ Prisma:
  • สร้างไฟล์ schema.prisma ที่อยู่ในโฟลเดอร์ prisma สำหรับกำหนดโครงสร้างของฐานข้อมูล

npx prisma init


  • จากนั้นแก้ไขไฟล์ schema.prisma เพื่อกำหนด Model สำหรับผู้ใช้:

model User {
  id        Int    @id @default(autoincrement())
  email     String @unique
  password  String
  createdAt DateTime @default(now())
}


  • หลังจากที่ตั้งค่าฐานข้อมูลเสร็จแล้ว ให้ทำการ Migrate โครงสร้างฐานข้อมูล:
npx prisma migrate dev --name init

ตอนนี้คุณก็พร้อมที่จะใช้ Prisma ในการติดต่อกับฐานข้อมูลแล้ว

การลงทะเบียนผู้ใช้ (Registration)

ในการสร้างระบบการลงทะเบียนเราต้องให้ผู้ใช้กรอกข้อมูล เช่น อีเมล และ รหัสผ่าน โดยระบบจะทำการเข้ารหัสรหัสผ่านก่อนเก็บลงในฐานข้อมูล เพื่อให้ปลอดภัยจากการโจมตีต่างๆ โดยการใช้ bcryptjs ในการเข้ารหัสรหัสผ่านก่อนเก็บ

ตัวอย่างการลงทะเบียนผู้ใช้ใน Next.js API route

// pages/api/auth/register.js
import bcrypt from 'bcryptjs';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { email, password } = req.body;

    // ตรวจสอบว่าอีเมลมีอยู่ในฐานข้อมูลหรือไม่
    const existingUser = await prisma.user.findUnique({
      where: { email },
    });

    if (existingUser) {
      return res.status(400).json({ message: 'User already exists' });
    }

    // เข้ารหัสรหัสผ่านก่อนเก็บ
    const hashedPassword = await bcrypt.hash(password, 12);

    // สร้างผู้ใช้ใหม่ในฐานข้อมูล
    const newUser = await prisma.user.create({
      data: {
        email,
        password: hashedPassword,
      },
    });

    return res.status(201).json(newUser);
  } else {
    res.status(405).json({ message: 'Method not allowed' });
  }
}

ในโค้ดนี้เราทำการตรวจสอบว่าอีเมลของผู้ใช้ที่กรอกมีอยู่ในฐานข้อมูลหรือไม่ ถ้ามีระบบจะแจ้งว่าผู้ใช้นั้นมีอยู่แล้ว แต่ถ้าไม่มีก็จะทำการเข้ารหัสรหัสผ่านและสร้างผู้ใช้ใหม่ในฐานข้อมูล

การล็อกอินผู้ใช้ (Login)

เมื่อผู้ใช้ทำการล็อกอิน เราต้องตรวจสอบว่าอีเมลและรหัสผ่านที่กรอกเข้ามาถูกต้องหรือไม่ โดยการเปรียบเทียบรหัสผ่านที่กรอกกับรหัสผ่านที่ถูกเข้ารหัสไว้ในฐานข้อมูล จากนั้น ถ้าถูกต้อง เราจะสร้าง JWT (JSON Web Token) เพื่อใช้ในการยืนยันตัวตนของผู้ใช้ในคำขอต่อไป

ตัวอย่างการล็อกอินใน Next.js API route

// pages/api/auth/login.js
import bcrypt from 'bcryptjs';
import jwt from 'jsonwebtoken';
import { PrismaClient } from '@prisma/client';

const prisma = new PrismaClient();

export default async function handler(req, res) {
  if (req.method === 'POST') {
    const { email, password } = req.body;

    // ค้นหาผู้ใช้ในฐานข้อมูล
    const user = await prisma.user.findUnique({
      where: { email },
    });

    if (!user) {
      return res.status(400).json({ message: 'User not found' });
    }

    // เปรียบเทียบรหัสผ่าน
    const isPasswordValid = await bcrypt.compare(password, user.password);
    if (!isPasswordValid) {
      return res.status(400).json({ message: 'Invalid password' });
    }

    // สร้าง JWT Token
    const token = jwt.sign({ userId: user.id }, 'your_jwt_secret', {
      expiresIn: '1h',
    });

    return res.status(200).json({ token });
  } else {
    res.status(405).json({ message: 'Method not allowed' });
  }
}

ในโค้ดนี้:

  1. ระบบจะค้นหาผู้ใช้จาก อีเมล ที่ผู้ใช้กรอก
  2. ถ้าพบผู้ใช้, ระบบจะทำการเปรียบเทียบ รหัสผ่านที่กรอก กับ รหัสผ่านที่เข้ารหัส ในฐานข้อมูล
  3. ถ้ารหัสผ่านถูกต้อง, ระบบจะสร้าง JWT Token และส่งกลับไปให้ผู้ใช้


การใช้งาน Token ในการยืนยันตัวตน

หลังจากที่ผู้ใช้ล็อกอินสำเร็จและได้รับ JWT Token, ผู้ใช้จะต้องส่ง Token นี้กลับมาในคำขอถัดไป เพื่อให้ระบบสามารถยืนยันตัวตนของผู้ใช้ได้

ตัวอย่างการป้องกัน API ด้วย JWT

// pages/api/protected.js
import jwt from 'jsonwebtoken';

export default function handler(req, res) {
  const token = req.headers['authorization']?.split(' ')[1];

  if (!token) {
    return res.status(401).json({ message: 'No token provided' });
  }

  try {
    const decoded = jwt.verify(token, 'your_jwt_secret');
    res.status(200).json({ message: 'This is a protected route', userId: decoded.userId });
  } catch (error) {
    res.status(401).json({ message: 'Invalid or expired token' });
  }
}

ในตัวอย่างนี้, ระบบจะตรวจสอบว่า JWT Token ที่ส่งมาพร้อมกับคำขอเป็น Token ที่ถูกต้อง หรือไม่ ถ้าถูกต้อง ระบบจะอนุญาตให้เข้าถึงข้อมูลที่ต้องการได้

สรุป

การจัดการ Authentication ใน Next.js เป็นกระบวนการที่ไม่ซับซ้อนและสามารถทำได้อย่างมีประสิทธิภาพ โดยใช้เครื่องมือที่ได้รับความนิยม เช่น bcryptjs สำหรับการเข้ารหัสรหัสผ่าน และ JWT สำหรับการสร้างและตรวจสอบ Token ซึ่งช่วยให้ระบบของเรามีความปลอดภัยและยืดหยุ่น

การใช้ Prisma ในการเชื่อมต่อฐานข้อมูลก็ทำให้การจัดการข้อมูลผู้ใช้มีความสะดวกและสามารถขยายได้ตามต้องการ โดยทั้งหมดนี้จะทำให้การสร้างระบบ Authentication ใน Next.js เป็นไปอย่างราบรื่นและปลอดภัย

การใช้ Image Optimization ใน Next.js: โหลดไว SEO ดี ประหยัดแบนด์วิธ!

เคยเจอปัญหาเว็บโหลดช้าเพราะรูปภาพขนาดใหญ่หรือเปล่า? 📷 ถ้าใช่ Next.js มีฟีเจอร์ Image Optimization ที่ช่วยให้รูปภาพโหลดเร็วขึ้น อัตโนมัติ ไม...