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

วันเสาร์ที่ 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 แล้ว! 🔥

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

การใช้งาน Middleware ใน Next.js

ถ้าพูดถึง Middleware หลายคนอาจนึกถึง Express.js ที่ใช้ตรวจสอบ Request ก่อนส่งไปยัง Handler แต่รู้ไหมว่า Next.js ก็มี Middleware เป็นของตัวเอง!

Middleware ใน Next.js ช่วยให้เราสามารถ ควบคุมการเข้าถึงหน้าเว็บ, ตรวจสอบสิทธิ์ (Authentication), Redirect, และ Modify Request/Response ได้ก่อนที่ผู้ใช้จะเข้าถึงหน้าเว็บจริง ๆ

ในบทความนี้ เราจะมาดูกันว่า Middleware ใน Next.js คืออะไร ใช้งานยังไง และเราสามารถนำไปใช้ทำอะไรได้บ้าง 🛠️🚀

🔥 Middleware ใน Next.js คืออะไร?

Middleware คือ โค้ดที่ทำงานอยู่ระหว่าง Request และ Response หรือพูดง่าย ๆ ก็คือ มันช่วยให้เราสามารถจัดการ Request ก่อนที่มันจะไปถึง API หรือ Page จริง ๆ

Next.js Middleware ทำงานที่ Edge หรือที่เรียกว่า Edge Functions ซึ่งหมายความว่า
✅ ทำงานเร็วมาก เพราะไม่ต้องรอโหลดทั้งเซิร์ฟเวอร์
✅ ใช้งานได้กับทุก Request ที่เข้ามา
✅ ลดภาระของ API Routes และ getServerSideProps

📌 ข้อดีของ Middleware

  • ตรวจสอบสิทธิ์ (Auth) ก่อนเข้าหน้าเว็บ
  • กำหนดเงื่อนไขสำหรับแต่ละ Route
  • Redirect หรือ Rewrite Request ได้
  • บล็อกหรือแก้ไข Header ของ Request


🚀 วิธีใช้ Middleware ใน Next.js

Middleware ใน Next.js จะถูกเก็บไว้ที่ไฟล์ middleware.ts หรือ middleware.js ใน root ของโปรเจกต์

🔹 สร้าง Middleware แรกของคุณ

ไฟล์ middleware.ts

import { NextRequest, NextResponse } from 'next/server'

export function middleware(req: NextRequest) {
  console.log('Middleware กำลังทำงาน...')
  return NextResponse.next() // ให้ Request ผ่านไปยังหน้าปลายทาง
}

จากนั้นรันเซิร์ฟเวอร์

npm run dev

ทุกครั้งที่มี Request เข้ามา Middleware จะทำงานก่อนส่งไปที่ Page หรือ API


🔑 ตัวอย่างการใช้งาน Middleware

✨ 1. การ Redirect ผู้ใช้

บางครั้งเราต้องการให้ผู้ใช้ถูก Redirect ไปยังหน้าอื่น โดยอัตโนมัติ

import { NextRequest, NextResponse } from 'next/server'

export function middleware(req: NextRequest) {
  const url = req.nextUrl

  if (url.pathname === '/old-page') {
    return NextResponse.redirect(new URL('/new-page', req.url))
  }

  return NextResponse.next()
}

✅ เมื่อผู้ใช้เข้าหน้า /old-page จะถูก Redirect ไปที่ /new-page อัตโนมัติ

🔐 2. ตรวจสอบสิทธิ์ก่อนเข้าหน้าเว็บ (Authentication)

สมมติว่าเรามีหน้า Dashboard ที่ต้องการให้เฉพาะผู้ใช้ที่ล็อกอินเข้าถึงได้

import { NextRequest, NextResponse } from 'next/server'

export function middleware(req: NextRequest) {
  const token = req.cookies.get('auth_token')

  if (!token) {
    return NextResponse.redirect(new URL('/login', req.url))
  }

  return NextResponse.next()
}

✅ ถ้าไม่มี Token ผู้ใช้จะถูกส่งไปที่ /login ทันที

🌍 3. เช็คประเทศของผู้ใช้ แล้วเปลี่ยนภาษาอัตโนมัติ

ถ้าต้องการ เปลี่ยนภาษาเว็บตามประเทศของผู้ใช้ เราสามารถใช้ Middleware เช็ค IP แล้ว Redirect ไปยังหน้าที่เหมาะสม

import { NextRequest, NextResponse } from 'next/server'

export function middleware(req: NextRequest) {
  const country = req.geo?.country || 'US' // ดึงค่าประเทศจาก IP

  if (country === 'TH') {
    return NextResponse.redirect(new URL('/th', req.url)) // เปลี่ยนไปหน้าเวอร์ชันภาษาไทย
  }

  return NextResponse.next()
}

✅ ถ้าผู้ใช้มาจากไทย จะถูกส่งไปที่ /th อัตโนมัติ

🔄 4. เปลี่ยน Headers ของ Request

บางครั้งเราต้องการ เพิ่ม Headers หรือแก้ไข Headers ก่อนส่งไปยัง API หรือ Page

import { NextRequest, NextResponse } from 'next/server'

export function middleware(req: NextRequest) {
  const response = NextResponse.next()
  response.headers.set('X-Custom-Header', 'HelloMiddleware')
  return response
}

✅ เพิ่ม Header X-Custom-Header: HelloMiddleware ในทุก Response

🛠 การกำหนด Middleware ให้ทำงานเฉพาะบางหน้า

บางครั้งเราอาจต้องการให้ Middleware ทำงาน แค่บางหน้า ไม่ใช่ทั้งหมด สามารถใช้ config.matcher ได้

import { NextRequest, NextResponse } from 'next/server'

export function middleware(req: NextRequest) {
  return NextResponse.next()
}

// ใช้ Middleware เฉพาะบาง Route
export const config = {
  matcher: ['/dashboard/:path*', '/profile/:path*'],
}

✅ Middleware จะทำงานเฉพาะหน้า /dashboard และ /profile เท่านั้น


📌 Middleware กับ API Routes ต่างกันยังไง?

Feature Middleware API Routes
ทำงานเมื่อไหร่? ก่อนส่งไปยัง Page หรือ API เมื่อมีการเรียก API
ทำอะไรได้บ้าง? Redirect, Auth, Modify Request รับ-ส่งข้อมูล API
ทำงานที่ไหน? Edge (เร็วมาก) Server (ปกติ)
ใช้เมื่อไหร่? ตรวจสอบสิทธิ์, Redirect, แก้ไข Headers สร้าง API สำหรับแอป
  • ถ้าต้องการ ดัก Request ก่อนถึงหน้าเว็บ → ใช้ Middleware
  • ถ้าต้องการ สร้าง API Endpoint สำหรับแอป → ใช้ API Routes


🎯 สรุป

Middleware ใน Next.js เป็นเครื่องมือที่ทรงพลังที่ช่วยให้เราสามารถ
✅ Redirect ผู้ใช้ ไปยังหน้าที่เหมาะสม
✅ ตรวจสอบสิทธิ์ ก่อนเข้าถึงข้อมูล
✅ เปลี่ยน Headers ของ Request/Response
✅ ตรวจสอบ IP, Geo Location และเปลี่ยนภาษาเว็บอัตโนมัติ

🔥 ถ้าโปรเจกต์ของคุณต้องการควบคุม Request ก่อนถึงหน้าเว็บ Middleware คือสิ่งที่คุณต้องใช้! 🚀

วันอาทิตย์ที่ 2 มีนาคม พ.ศ. 2568

การใช้ API Routes เพื่อสร้าง Backend ใน Next.js

ถ้าพูดถึง Next.js หลายคนคงนึกถึง Frontend Framework ที่ช่วยพัฒนาเว็บได้เร็วและแรง แต่รู้หรือเปล่าว่า Next.js ก็มี Backend ในตัว ด้วย?

ใช่แล้ว! Next.js มาพร้อมกับ API Routes ที่ให้เราสร้าง Backend API ได้ง่าย ๆ โดยไม่ต้องใช้ Express, NestJS หรือพวก Backend Framework อื่น ๆ

ในบทความนี้ เราจะมาทำความรู้จัก API Routes ใน Next.js ว่ามันคืออะไร ใช้งานยังไง และมีประโยชน์อะไรบ้าง ถ้าพร้อมแล้วไปลุยกันเลย! 🚀

🤔 API Routes คืออะไร?

API Routes คือฟีเจอร์ของ Next.js ที่ให้เราสร้าง REST API ได้โดยตรงในโปรเจกต์ Next.js เอง โดยไม่ต้องเซ็ตเซิร์ฟเวอร์แยก

📌 ข้อดีของ API Routes

✅ ไม่ต้องใช้ Backend แยก – Next.js จัดการให้
✅ ใช้ JavaScript/TypeScript ล้วน ๆ – ไม่ต้องเรียนรู้ภาษาใหม่
✅ รองรับ Serverless Functions – ทำงานบน Vercel, AWS Lambda, Firebase Functions ได้เลย
✅ ใช้ร่วมกับ Frontend ง่าย – อยู่ในโปรเจกต์เดียวกัน

ถ้าเทียบกับการใช้ Node.js + Express ที่ต้องเซ็ตเซิร์ฟเวอร์เอง API Routes ของ Next.js จะง่ายกว่าเยอะ!

🛠 สร้าง API Routes แรกของคุณ

ใน Next.js ไฟล์ API Routes จะอยู่ใน /pages/api/ เช่น

📂 โครงสร้างโฟลเดอร์

my-next-app/
 ├── pages/
 │   ├── index.js
 │   ├── about.js
 │   ├── api/       <-- โฟลเดอร์ API
 │   │   ├── hello.js   <-- ไฟล์ API Route
 │   │   ├── users.js
 │   │   ├── posts.js

ลองสร้างไฟล์ /pages/api/hello.js แล้วใส่โค้ดนี้ลงไป

export default function handler(req, res) {
  res.status(200).json({ message: 'สวัสดีจาก API Routes!' })
}

✨ ลองรันเซิร์ฟเวอร์

npm run dev
# หรือ
yarn dev

แล้วเข้า http://localhost:3000/api/hello จะได้ JSON แบบนี้

{
  "message": "สวัสดีจาก API Routes!"
}

ง่ายมากใช่ไหม? ไม่ต้องติดตั้ง Express หรือเซ็ต Server อะไรให้ยุ่งยากเลย!

🚀 การใช้ HTTP Methods (GET, POST, PUT, DELETE)

API Routes รองรับทุก HTTP Method เช่น GET, POST, PUT, DELETE โดยเช็คจาก req.method

✨ ตัวอย่าง API รองรับหลาย Method

ไฟล์ /pages/api/users.js

export default function handler(req, res) {
  if (req.method === 'GET') {
    res.status(200).json({ users: ['Alice', 'Bob', 'Charlie'] })
  } else if (req.method === 'POST') {
    res.status(201).json({ message: 'สร้างผู้ใช้ใหม่เรียบร้อย!' })
  } else {
    res.status(405).json({ error: 'Method ไม่รองรับ' })
  }
}

🔹 GET → ดึงข้อมูลผู้ใช้
🔹 POST → สร้างผู้ใช้ใหม่
🔹 อื่น ๆ → ส่ง 405 Method Not Allowed

ลองยิง API ดู! 🚀

curl -X GET http://localhost:3000/api/users
curl -X POST http://localhost:3000/api/users


🔄 อ่านค่า Query Parameters

ถ้าต้องการดึงค่าจาก Query String (เช่น /api/user?id=123) เราสามารถใช้ req.query ได้เลย

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

export default function handler(req, res) {
  const { id } = req.query

  if (!id) {
    return res.status(400).json({ error: 'กรุณาระบุ id' })
  }

  res.status(200).json({ user: { id, name: 'John Doe' } })
}

✨ ทดสอบ API

curl http://localhost:3000/api/user?id=456

📌 output

{
  "user": { "id": "456", "name": "John Doe" }
}


📬 รับข้อมูลจาก Body (POST Method)

ถ้าต้องการรับข้อมูลจาก Body ของ Request เช่นเวลาส่งฟอร์มหรือ JSON Data เราสามารถใช้ req.body ได้เลย

ไฟล์ /pages/api/login.js

export default function handler(req, res) {
  if (req.method !== 'POST') {
    return res.status(405).json({ error: 'Method ไม่รองรับ' })
  }

  const { username, password } = req.body

  if (username === 'admin' && password === '1234') {
    res.status(200).json({ message: 'เข้าสู่ระบบสำเร็จ!' })
  } else {
    res.status(401).json({ error: 'ชื่อผู้ใช้หรือรหัสผ่านไม่ถูกต้อง' })
  }
}

✨ ทดสอบ API

curl -X POST http://localhost:3000/api/login -H "Content-Type: application/json" -d '{"username": "admin", "password": "1234"}'

📌 output

{
  "message": "เข้าสู่ระบบสำเร็จ!"
}

🔒 ใช้ Middleware กับ API Routes

ถ้าต้องการตรวจสอบ JWT Token หรือทำ Authentication ก่อนเข้าถึง API สามารถใช้ Middleware ได้ง่าย ๆ

ไฟล์ /pages/api/secure.js

export default function handler(req, res) {
  const { authorization } = req.headers

  if (!authorization || authorization !== 'Bearer mysecrettoken') {
    return res.status(403).json({ error: 'ไม่ได้รับอนุญาต' })
  }

  res.status(200).json({ message: 'เข้าถึงข้อมูลสำเร็จ!' })
}

✨ ทดสอบ API (ล้มเหลว)

curl http://localhost:3000/api/secure

📌 output

{
  "error": "ไม่ได้รับอนุญาต"
}

✨ ทดสอบ API (สำเร็จ)

curl -H "Authorization: Bearer mysecrettoken" http://localhost:3000/api/secure

📌 output

{
  "message": "เข้าถึงข้อมูลสำเร็จ!"
}

🎯 สรุป

API Routes เป็นฟีเจอร์ที่ช่วยให้เราสร้าง Backend API ใน Next.js ได้ง่าย ๆ โดยไม่ต้องติดตั้งเซิร์ฟเวอร์แยก เหมาะกับการทำงานแบบ Fullstack ที่ต้องการพัฒนา Frontend และ Backend ไปพร้อมกัน

📌 จุดเด่นของ API Routes

✅ ใช้งานง่าย – ไม่ต้องเซ็ตเซิร์ฟเวอร์เอง
✅ รองรับ HTTP Methods (GET, POST, PUT, DELETE)
✅ ใช้ Query Parameters และ Request Body ได้
✅ รองรับ Middleware เช่น Authentication

ถ้าคุณใช้ Next.js อยู่แล้ว ลองใช้ API Routes ดู แล้วจะรู้ว่ามัน โคตรสะดวก! 🚀

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

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