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

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

วิธีป้องกันหน้าเว็บที่ต้องล็อกอินก่อนเข้าใช้งานใน Next.js

อย่าปล่อยให้ใครเข้ามาเที่ยวเว็บเราฟรีๆ! 😆

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

ในบทความนี้ เราจะมาดูกันว่า Next.js + NextAuth.js ใช้ทำ Protected Route (หน้าที่ต้องล็อกอินก่อนเข้า) ได้ยังไง

🚀 ทำไมต้องป้องกันหน้าเว็บ?

✅ ป้องกันข้อมูลสำคัญ

  • ถ้าเว็บมีข้อมูลผู้ใช้ ห้ามให้คนที่ไม่ได้ล็อกอินเข้าถึง

✅ เพิ่มความปลอดภัย

  • ไม่เปิดช่องให้ Bot หรือ Hacker แอบเข้ามาดูข้อมูล

✅ UX ดีขึ้น

  •     ถ้าไม่ได้ล็อกอิน 👉 Redirect ไปหน้า Login
  •     ล็อกอินแล้ว 👉 เข้าใช้งานได้ปกติ

สรุป: ทำให้เว็บ ปลอดภัย + เป็นระเบียบ + ใช้งานง่าย


🔥 วิธีทำ Protected Route ใน Next.js

1️⃣ ติดตั้ง NextAuth.js

ถ้ายังไม่มี NextAuth.js ให้ติดตั้งก่อน

npm install next-auth

2️⃣ ตั้งค่า NextAuth.js

สร้างไฟล์ pages/api/auth/[...nextauth].js

import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";

export default NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
});

💡 Tip: เราใช้ Google Login แต่คุณเปลี่ยนไปใช้ Auth0, GitHub, หรือ Email/Password ได้

3️⃣ ตั้งค่า ENV

สร้างไฟล์ .env.local แล้วใส่ค่า

GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
NEXTAUTH_SECRET=your-random-secret
NEXTAUTH_URL=http://localhost:3000


🛑 ป้องกันหน้าที่ต้องล็อกอิน

❌ วิธีที่ 1: เช็กใน Component

import { useSession, signIn } from "next-auth/react";

export default function Dashboard() {
  const { data: session, status } = useSession();

  if (status === "loading") return <p>Loading...</p>;
  if (!session) return <button onClick={() => signIn()}>Login to access</button>;

  return <h1>Welcome to your Dashboard, {session.user.name}!</h1>;
}

🔹 อธิบายโค้ด:
  •     ถ้ากำลังโหลด ให้แสดง Loading
  •     ถ้าไม่ได้ล็อกอิน ให้แสดงปุ่ม Login
  •     ถ้าล็อกอินแล้ว แสดงข้อมูลได้ปกติ

🚀 วิธีที่ 2: Redirect ไปหน้า Login อัตโนมัติ

ใช้ getServerSideProps เช็กสิทธิ์ก่อนโหลดหน้า

import { getSession } from "next-auth/react";

export async function getServerSideProps(context) {
  const session = await getSession(context);

  if (!session) {
    return {
      redirect: {
        destination: "/login",
        permanent: false,
      },
    };
  }

  return {
    props: { session },
  };
}

export default function Dashboard({ session }) {
  return <h1>Welcome, {session.user.name}!</h1>;
}

🔹 อธิบายโค้ด:
  •     ถ้า ไม่ได้ล็อกอิน 👉 Redirect ไป /login
  •     ถ้า ล็อกอินแล้ว 👉 ให้เข้า Dashboard ได้

✅ ข้อดี:
  •     ป้องกันตั้งแต่ฝั่งเซิร์ฟเวอร์
  •     SEO Friendly เพราะไม่ได้บล็อกการโหลดหน้า

🔒 วิธีที่ 3: สร้าง Middleware ป้องกันทุกหน้า

ใช้ middleware.ts เพื่อบังคับให้ล็อกอินทุกครั้งที่เข้า /dashboard

สร้างไฟล์ middleware.ts

import { NextRequest, NextResponse } from "next/server";

export function middleware(req: NextRequest) {
  const token = req.cookies.get("next-auth.session-token");

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

  return NextResponse.next();
}

export const config = {
  matcher: "/dashboard/:path*",
};

🔹 อธิบายโค้ด:
  •     ถ้าไม่มี Token 👉 Redirect ไป /login
  •     ถ้ามี Token 👉 อนุญาตให้เข้า /dashboard ได้

✅ ข้อดี:
  •     ป้องกันทุกหน้าใน /dashboard/ อัตโนมัติ
  •     ไม่ต้องใส่โค้ดป้องกันทุกไฟล์

🎨 สร้างหน้า Login

สร้าง pages/login.js

import { signIn } from "next-auth/react";

export default function Login() {
  return (
    <div>
      <h1>Login</h1>
      <button onClick={() => signIn("google")}>Login with Google</button>
    </div>
  );
}

🔹 อธิบายโค้ด:
  •     ปุ่มเดียวจบ! กดแล้วล็อกอินผ่าน Google


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

1️⃣ ควรใช้วิธีไหนดีที่สุด?

ขึ้นอยู่กับโปรเจ็กต์:
  •     หน้าเดียวกัน (Client-side protection) 👉 useSession()
  •     ป้องกันทุกหน้า (Server-side protection) 👉 getServerSideProps()
  •     ป้องกันโฟลเดอร์ (Global protection) 👉 middleware.ts

2️⃣ NextAuth.js รองรับอะไรบ้าง?

  •     Google, Facebook, GitHub, Apple, Twitter
  •     Email/Password
  •     Magic Link

3️⃣ ถ้าอยากให้บางหน้าล็อกอิน แต่บางหน้าไม่ต้องทำไง?

  •     ใช้ Middleware เฉพาะโฟลเดอร์
  •     เช็ก useSession() ใน Component

🎉 สรุป

  •     ป้องกันหน้าเว็บที่ต้องล็อกอินก่อนเข้าใช้งาน ได้หลายวิธี
  •     ใช้ useSession() ถ้าต้องการป้องกันจากฝั่ง Client
  •     ใช้ getServerSideProps() ถ้าต้องการ Redirect อัตโนมัติ
  •     ใช้ middleware.ts ถ้าต้องการป้องกันทั้งโฟลเดอร์
ลองทำดู แล้วจะติดใจ! 😉

วันจันทร์ที่ 24 มีนาคม พ.ศ. 2568

วิธีใช้ Auth0 กับ Next.js แบบเข้าใจง่าย

ถ้าขี้เกียจทำระบบล็อกอินเอง ให้ Auth0 จัดการให้เถอะ!

Auth0 เป็นแพลตฟอร์มจัดการการยืนยันตัวตน (Authentication) ที่ช่วยให้เราทำระบบล็อกอินได้เร็วขึ้น โดยไม่ต้องมานั่งเขียนโค้ดยาวๆ ทำให้เว็บปลอดภัยขึ้นแบบไม่ต้องปวดหัว

ในบทความนี้ เราจะมาใช้ Auth0 กับ Next.js เพื่อทำระบบล็อกอินที่รองรับ OAuth (Google, Facebook ฯลฯ) และ Email/Password ได้ง่ายๆ


🚀 ทำไมต้องใช้ Auth0?

✅ ลดเวลาพัฒนา

  •     ไม่ต้องสร้างระบบยืนยันตัวตนเอง
  •     มี UI สำเร็จรูปให้ใช้เลย

✅ รองรับหลายวิธี

  •     ล็อกอินด้วย Google, Facebook, Apple, GitHub ฯลฯ
  •     ใช้ Magic Link หรือ OTP ก็ได้
  •     ใช้ Username/Password แบบปกติก็ได้

✅ ปลอดภัยกว่า

  •     มีการเข้ารหัสและป้องกันแฮก
  •     รองรับ MFA (Multi-Factor Authentication)


สรุปง่ายๆ Auth0 = เร็ว + ปลอดภัย + ใช้งานง่าย


🎯 มาเริ่มกันเลย!

1️⃣ สร้างโปรเจ็กต์ Next.js

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

npx create-next-app@latest auth0-demo
cd auth0-demo
npm install

2️⃣ สมัครและตั้งค่า Auth0

  1.     ไปที่ Auth0 Dashboard แล้วสมัครบัญชี
  2.     สร้าง Application ใหม่
    • เลือก Single Page Application
    • ใส่ Callback URL: http://localhost:3000/api/auth/callback/auth0
    • ใส่ Logout URL: http://localhost:3000/
  3. คัดลอก Client ID และ Client Secret


3️⃣ ติดตั้ง NextAuth.js (ใช้ Auth0 เป็น Provider)

ติดตั้งแพ็กเกจที่ต้องใช้

npm install next-auth @auth0/nextjs-auth0

4️⃣ ตั้งค่า NextAuth.js

สร้างไฟล์ pages/api/auth/[...nextauth].js

import NextAuth from "next-auth";
import Auth0Provider from "next-auth/providers/auth0";

export default NextAuth({
  providers: [
    Auth0Provider({
      clientId: process.env.AUTH0_CLIENT_ID,
      clientSecret: process.env.AUTH0_CLIENT_SECRET,
      issuer: process.env.AUTH0_ISSUER,
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
});

5️⃣ ตั้งค่า ENV

สร้างไฟล์ .env.local แล้วใส่ค่าเหล่านี้

AUTH0_CLIENT_ID=your-client-id
AUTH0_CLIENT_SECRET=your-client-secret
AUTH0_ISSUER=https://your-auth0-domain/
NEXTAUTH_SECRET=your-random-secret
NEXTAUTH_URL=http://localhost:3000

💡 Tip: ค่า NEXTAUTH_SECRET ใช้คำสั่งนี้สร้างแบบสุ่มได้

openssl rand -base64 32

6️⃣ สร้างปุ่ม Login / Logout

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

import { useSession, signIn, signOut } from "next-auth/react";

export default function Home() {
  const { data: session } = useSession();

  return (
    <div>
      <h1>Next.js + Auth0</h1>
      {session ? (
        <>
          <p>Welcome, {session.user.name}!</p>
          <button onClick={() => signOut()}>Logout</button>
        </>
      ) : (
        <button onClick={() => signIn("auth0")}>Login with Auth0</button>
      )}
    </div>
  );
}

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

  •     ใช้ useSession() เช็กว่าผู้ใช้ล็อกอินหรือยัง
  •     ถ้าล็อกอินแล้ว แสดงชื่อ + ปุ่ม Logout
  •     ถ้ายังไม่ล็อกอิน แสดงปุ่ม Login


🔥 ทดสอบใช้งาน

  1.     รันเซิร์ฟเวอร์ npm run dev
  2.     เข้าไปที่หน้าเว็บ http://localhost:3000
  3.     กดปุ่ม "Login with Auth0"
  4.     ล็อกอินผ่าน Google หรือ Email/Password
  5.     ถ้าสำเร็จจะกลับมาหน้าเว็บและแสดงชื่อ! 🎉


🎨 ทำหน้า Profile

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

import { useUser } from "@auth0/nextjs-auth0/client";

export default function Profile() {
  const { user, error, isLoading } = useUser();

  if (isLoading) return <p>Loading...</p>;
  if (error) return <p>Error: {error.message}</p>;

  return (
    user && (
      <div>
        <h1>{user.name}</h1>
        <p>Email: {user.email}</p>
        <img src={user.picture} alt={user.name} width={100} />
      </div>
    )
  );
}

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

  •     ใช้ useUser() ดึงข้อมูลผู้ใช้จาก Auth0
  •     แสดง ชื่อ, อีเมล, รูปโปรไฟล์


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

1️⃣ Auth0 ใช้ฟรีไหม?

ใช่! แต่แผนฟรีจำกัด 7,000 ล็อกอินต่อเดือน ถ้าใช้เยอะกว่านี้ต้องอัปเกรด

2️⃣ รองรับ Social Login อะไรบ้าง?

Google, Facebook, Apple, GitHub, Twitter ฯลฯ

3️⃣ ถ้าอยากใช้ Magic Link ต้องทำไง?

Auth0 รองรับ Passwordless Login (Magic Link, OTP) แค่เปิดใช้งานใน Dashboard


🎉 สรุป

  •     Auth0 ช่วยให้ทำระบบล็อกอินได้เร็วขึ้น
  •     ใช้ NextAuth.js เชื่อม Auth0 กับ Next.js
  •     รองรับ Social Login, Email/Password, Magic Link
  •     ปลอดภัย ไม่ต้องจัดการรหัสผ่านเอง

ลองทำดู แล้วจะติดใจ! 😉

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

วิธีใช้ Magic Link Authentication ใน Next.js แบบเข้าใจง่าย

ถ้าเบื่อรหัสผ่าน มาลอง Magic Link กันเถอะ!

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

ในบทความนี้ เราจะมาดูกันว่า Next.js ใช้ Magic Link ได้ยังไง โดยใช้ NextAuth.js (ตัวช่วยจัดการการยืนยันตัวตนใน Next.js) พร้อมกับ Resend (บริการส่งอีเมลที่ใช้ง่ายและเร็ว)

🎩 ทำไมต้อง Magic Link?

✅ ไม่ต้องจำรหัสผ่าน

  • ชีวิตเรามีรหัสผ่านเยอะเกินไปแล้ว! Magic Link ตัดปัญหานี้ออกไป

✅ ปลอดภัยกว่ารหัสผ่านปกติ

  •     ไม่มีรหัสผ่านให้แฮก (เพราะไม่มีเลย 🤣)
  •     ใช้ one-time link (ลิงก์ใช้ได้ครั้งเดียว) ลดความเสี่ยง

✅ UX ดีขึ้น

  •     ล็อกอินง่าย ไม่ต้องพิมพ์อะไรเยอะ
  •     ลดปัญหา "ลืมรหัสผ่าน"


สรุป: Magic Link = ง่าย + ปลอดภัย + ดีต่อผู้ใช้


🚀 มาเริ่มกันเลย!

1️⃣ สร้างโปรเจ็กต์ Next.js

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

npx create-next-app@latest magic-link-demo
cd magic-link-demo
npm install

2️⃣ ติดตั้ง NextAuth.js และ Resend

npm install next-auth resend

3️⃣ ตั้งค่า NextAuth.js

สร้างไฟล์ pages/api/auth/[...nextauth].js

import NextAuth from "next-auth";
import EmailProvider from "next-auth/providers/email";
import { Resend } from "resend";

const resend = new Resend(process.env.RESEND_API_KEY);

export default NextAuth({
  providers: [
    EmailProvider({
      async sendVerificationRequest({ identifier: email, url }) {
        await resend.emails.send({
          from: "no-reply@yourdomain.com",
          to: email,
          subject: "Magic Link Login",
          html: `<p>Click <a href="${url}">here</a> to log in.</p>`,
        });
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
});

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

  •     ใช้ EmailProvider จาก NextAuth.js
  •     เมื่อผู้ใช้ใส่อีเมล ระบบจะส่ง Magic Link ไปที่อีเมลนั้น
  •     ใช้ Resend เป็นตัวช่วยส่งอีเมล
  •     ลิงก์ที่ส่งไปเป็นแบบ one-time link


🎨 สร้างหน้า Login

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

import { signIn } from "next-auth/react";

export default function Login() {
  const handleLogin = async (e) => {
    e.preventDefault();
    const email = e.target.email.value;
    await signIn("email", { email });
  };

  return (
    <div>
      <h1>Magic Link Login</h1>
      <form onSubmit={handleLogin}>
        <input type="email" name="email" placeholder="Enter your email" required />
        <button type="submit">Send Magic Link</button>
      </form>
    </div>
  );
}

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

  •     มีฟอร์มให้ผู้ใช้กรอกอีเมล
  •     กดปุ่มแล้วระบบจะเรียก signIn("email", { email }) เพื่อขอ Magic Link
  •     NextAuth.js จะจัดการส่งอีเมลให้เอง


🎯 ทดสอบใช้งาน

  1.     รันเซิร์ฟเวอร์ npm run dev
  2.     เข้าไปที่ /login
  3.     ใส่อีเมล แล้วกดส่ง
  4.     เปิดอีเมล กดลิงก์ แล้วเข้าสู่ระบบ! 🎉



🔥 เพิ่มเติม: ตั้งค่า ENV

สร้างไฟล์ .env.local

NEXTAUTH_SECRET=your-secret-key
RESEND_API_KEY=your-resend-api-key
NEXTAUTH_URL=http://localhost:3000


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

1️⃣ ถ้าไม่มีอีเมล จะล็อกอินยังไง?

Magic Link ต้องใช้อีเมลเท่านั้น ถ้าผู้ใช้ไม่มีอีเมล อาจต้องใช้ OAuth (เช่น Google, Facebook)

2️⃣ Magic Link ปลอดภัยจริงไหม?

ค่อนข้างปลอดภัย แต่ควร:

  •     ใช้ one-time link
  •     ลิงก์ควรหมดอายุเร็ว (เช่น 10 นาที)
  •     ใช้ HTTPS เสมอ

3️⃣ ถ้าอีเมลไปไม่ถึงทำไง?

  •     เช็กโฟลเดอร์ Spam
  •     ใช้อีเมลจากผู้ให้บริการที่น่าเชื่อถือ
  •     ลองเปลี่ยนไปใช้ SMTP แทน Resend


🎉 สรุป

  •     Magic Link คือการล็อกอินแบบไม่ใช้รหัสผ่าน
  •     NextAuth.js + Resend ช่วยให้ใช้งาน Magic Link ได้ง่าย
  •     UX ดีขึ้น ปลอดภัยขึ้น และลดปัญหาลืมรหัสผ่าน

ลองทำกันดู แล้วจะติดใจ! 😉

วันเสาร์ที่ 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 สวยๆ เท่านั้น! 🚀

วันศุกร์ที่ 21 มีนาคม พ.ศ. 2568

การใช้ Firebase Authentication กับ Next.js – ล็อกอินง่ายๆ ด้วย Google, Email, GitHub

อยากให้เว็บ Next.js ของเรามีระบบล็อกอินด้วย Google, Email หรือ GitHub ไหม? 🔑
Firebase Authentication เป็นตัวช่วยที่ ฟรี, ใช้งานง่าย, และ ปลอดภัย

วันนี้เราจะมาทำระบบ Sign-up & Login ด้วย Firebase Auth ใน Next.js แบบครบๆ พร้อมโค้ดตัวอย่าง! 🚀

🎯 เราจะทำอะไรบ้าง?

✅ สมัครสมาชิก & ล็อกอินด้วย Email/Password
✅ ล็อกอินด้วย Google, GitHub
✅ จัดการ Session ด้วย Firebase
✅ ใช้ Firebase SDK ใน Next.js

💡 ไม่ต้องทำระบบ Auth เอง! Firebase จัดการให้หมด แค่เขียนโค้ดเชื่อมต่อก็ใช้ได้เลย 🔥

🔥 ตั้งค่า Firebase Authentication

🛠️ 1. สมัคร Firebase และสร้างโปรเจกต์

  1. เข้าไปที่ Firebase Console
  2. กด "Add Project" → ตั้งชื่อโปรเจกต์ → กด "Continue"
  3. กด "Enable Google Analytics" หรือ ปิดก็ได้ → กด "Create Project"

🔑 2. เปิดใช้งาน Authentication

  1. ไปที่ "Build" → "Authentication"
  2. กด "Get Started"
  3. ไปที่ "Sign-in method"
  4. เปิดการใช้งาน Email/Password, Google, GitHub

🔗 3. ตั้งค่า Web API Key

  1. ไปที่ "Project settings" (ไอคอนรูปเฟือง)
  2. ไปที่ "General" → "Your apps" → กด "Web app"
  3. ตั้งชื่อแอป → กด "Register app"
  4. คัดลอก Firebase Config ไว้


⚙️ ติดตั้ง Firebase SDK ใน Next.js

1. สร้างโปรเจกต์ Next.js

    npx create-next-app my-firebase-auth
    cd my-firebase-auth
    npm install firebase

2. สร้างไฟล์ firebase.js เพื่อเชื่อมต่อ Firebase

📌 โค้ด: lib/firebase.js

import { initializeApp } from "firebase/app";
import { getAuth } from "firebase/auth";

const firebaseConfig = {
  apiKey: "YOUR_API_KEY",
  authDomain: "YOUR_AUTH_DOMAIN",
  projectId: "YOUR_PROJECT_ID",
  storageBucket: "YOUR_STORAGE_BUCKET",
  messagingSenderId: "YOUR_MESSAGING_SENDER_ID",
  appId: "YOUR_APP_ID",
};

const app = initializeApp(firebaseConfig);
export const auth = getAuth(app);

💡 อย่าลืมเปลี่ยน YOUR_API_KEY เป็นค่าจริงจาก Firebase!



✉️ สมัครสมาชิก & ล็อกอินด้วย Email/Password

📌 โค้ด: pages/auth.js

import { useState } from "react";
import { auth } from "../lib/firebase";
import { createUserWithEmailAndPassword, signInWithEmailAndPassword } from "firebase/auth";

export default function AuthPage() {
  const [email, setEmail] = useState("");
  const [password, setPassword] = useState("");
  const [message, setMessage] = useState("");

  const signUp = async () => {
    try {
      await createUserWithEmailAndPassword(auth, email, password);
      setMessage("Signup successful!");
    } catch (error) {
      setMessage(error.message);
    }
  };

  const login = async () => {
    try {
      await signInWithEmailAndPassword(auth, email, password);
      setMessage("Login successful!");
    } catch (error) {
      setMessage(error.message);
    }
  };

  return (
    <div>
      <h1>Firebase Auth</h1>
      <input type="email" placeholder="Email" onChange={(e) => setEmail(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>
      <p>{message}</p>
    </div>
  );
}

✅ กรอก Email & Password แล้วสมัครหรือล็อกอินได้เลย!


🔵 ล็อกอินด้วย Google

📌 โค้ด: pages/auth.js (เพิ่มปุ่ม Google Sign-in)

import { GoogleAuthProvider, signInWithPopup } from "firebase/auth";

const loginWithGoogle = async () => {
  try {
    const provider = new GoogleAuthProvider();
    await signInWithPopup(auth, provider);
    setMessage("Login with Google successful!");
  } catch (error) {
    setMessage(error.message);
  }
};

// เพิ่มปุ่ม Login with Google
<button onClick={loginWithGoogle}>Login with Google</button>;

✅ กดปุ่ม → เลือกบัญชี Google → ล็อกอินสำเร็จ!


🛡️ จัดการ Session ด้วย Firebase

Firebase มี onAuthStateChanged ให้เราตรวจสอบว่าผู้ใช้ล็อกอินอยู่หรือไม่

📌 โค้ด: pages/index.js


import { useEffect, useState } from "react";
import { auth } from "../lib/firebase";
import { onAuthStateChanged, signOut } from "firebase/auth";

export default function Home() {
  const [user, setUser] = useState(null);

  useEffect(() => {
    const unsubscribe = onAuthStateChanged(auth, (user) => {
      setUser(user);
    });
    return () => unsubscribe();
  }, []);

  return (
    <div>
      <h1>Welcome {user ? user.email : "Guest"}</h1>
      {user ? (
        <button onClick={() => signOut(auth)}>Logout</button>
      ) : (
        <a href="/auth">Go to Login</a>
      )}
    </div>
  );
}

✅ ถ้าล็อกอินอยู่จะแสดง Email ของผู้ใช้
✅ ถ้ายังไม่ล็อกอินจะแสดงปุ่ม Go to Login


🚀 ทดสอบระบบ

  1. รันเซิร์ฟเวอร์ npm run dev
  2. เปิด http://localhost:3000/auth
  3. ลองสมัครสมาชิก & ล็อกอิน
  4. เช็คหน้าแรก ว่ามี Session หรือไม่?

🎉 เรียบร้อย! Firebase Auth ใช้งานได้แล้ว!


🎯 สรุป

✅ ใช้ Firebase Authentication ใน Next.js ได้ง่ายๆ
✅ รองรับ Email/Password, Google, GitHub
✅ Session จัดการอัตโนมัติ ด้วย Firebase SDK
✅ ใช้ onAuthStateChanged เช็กสถานะผู้ใช้

🚀 พร้อมใช้ในโปรเจกต์จริง! แค่เพิ่ม UI สวยๆ และ Database ก็เปิดให้คนใช้ได้เลย!

วันพฤหัสบดีที่ 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 แล้ว! 🔥

วันจันทร์ที่ 17 มีนาคม พ.ศ. 2568

วิธีใช้ OAuth (Google, Facebook, GitHub) กับ NextAuth.js

ถ้าพูดถึงการทำระบบล็อกอินแบบ Single Sign-On (SSO) ในแอปพลิเคชันเว็บที่ใช้ Next.js ก็คงหนีไม่พ้น NextAuth.js ที่เป็นไลบรารีสุดเทพ ช่วยให้เราสามารถจัดการเรื่องการยืนยันตัวตน (Authentication) ได้ง่ายมาก ๆ แถมยังรองรับ OAuth จากหลายแพลตฟอร์ม เช่น Google, Facebook, GitHub แบบไม่ต้องปวดหัวกับการเขียนโค้ดเยอะ

บทความนี้จะพาไปดูวิธีใช้งาน OAuth กับ NextAuth.js ตั้งแต่ต้นจนจบ รับรองว่าทำตามได้ง่าย ไม่งงแน่นอน! 🚀

🧐 NextAuth.js คืออะไร?

NextAuth.js เป็นไลบรารีที่ช่วยจัดการ Authentication บน Next.js โดยรองรับทั้ง

✅ Email-based login
✅ Credentials-based login
✅ OAuth (เช่น Google, Facebook, GitHub)
✅ JWT และ Database sessions

ความเจ๋งคือ ไม่ต้องเซ็ต Backend เอง เพราะมันจัดการให้หมดแล้ว แค่ติดตั้งและคอนฟิกให้ถูกต้องก็ใช้งานได้เลย!

🛠️ ติดตั้ง NextAuth.js

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

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

จากนั้นก็เปิดไฟล์ .env.local แล้วตั้งค่าตัวแปรแวดล้อมที่เกี่ยวข้องกับ OAuth ที่เราจะใช้ (เช่น Google, Facebook, GitHub)


🔑 การตั้งค่า OAuth Provider

1️⃣ ตั้งค่า Google OAuth

ไปที่ Google Cloud Console (https://console.cloud.google.com/) แล้วทำตามนี้:

  1. สร้างโปรเจกต์ใหม่
  2. ไปที่ APIs & Services > Credentials
  3. กด Create Credentials > OAuth Client ID
  4. ตั้งค่า Authorized redirect URIs เป็น: http://localhost:3000/api/auth/callback/google
  5. ก๊อบปี้ Client ID และ Client Secret มาใส่ใน .env.local


GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret

2️⃣ ตั้งค่า Facebook OAuth

ไปที่ Meta for Developers (https://developers.facebook.com/) แล้วทำตามนี้:

  1. สร้างแอปใหม่
  2. ไปที่ Settings > Basic แล้วจด App ID และ App Secret
  3. ไปที่ Facebook Login > Settings แล้วตั้งค่า Valid OAuth Redirect URIs เป็น: http://localhost:3000/api/auth/callback/facebook
  4. เพิ่มค่าเหล่านี้ใน .env.local


FACEBOOK_CLIENT_ID=your-facebook-app-id
FACEBOOK_CLIENT_SECRET=your-facebook-app-secret

3️⃣ ตั้งค่า GitHub OAuth

ไปที่ GitHub Developer Settings (https://github.com/settings/developers) แล้วทำตามนี้:

  1. กด New OAuth App
  2. ตั้งค่า Authorization callback URL เป็น: http://localhost:3000/api/auth/callback/github
  3. ก๊อบปี้ Client ID และ Client Secret มาใส่ใน .env.local


GITHUB_CLIENT_ID=your-github-client-id
GITHUB_CLIENT_SECRET=your-github-client-secret

🔌 คอนฟิก NextAuth.js

สร้างไฟล์ pages/api/auth/[...nextauth].js แล้วใส่โค้ดนี้:

import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";
import FacebookProvider from "next-auth/providers/facebook";
import GitHubProvider from "next-auth/providers/github";

export default NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
    FacebookProvider({
      clientId: process.env.FACEBOOK_CLIENT_ID,
      clientSecret: process.env.FACEBOOK_CLIENT_SECRET,
    }),
    GitHubProvider({
      clientId: process.env.GITHUB_CLIENT_ID,
      clientSecret: process.env.GITHUB_CLIENT_SECRET,
    }),
  ],
  callbacks: {
    async session({ session, token }) {
      session.user.id = token.sub;
      return session;
    },
  },
});

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

  • เรา import NextAuth และเพิ่ม Google, Facebook, GitHub เป็น OAuth Providers
  • ใช้ Environment Variables (process.env...) เพื่อความปลอดภัย
  • เพิ่ม Callback function เพื่อให้ Session มีค่า user.id


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

ไปที่ pages/index.js แล้วเพิ่มปุ่มล็อกอิน / ออกจากระบบ

import { signIn, signOut, useSession } from "next-auth/react";

export default function Home() {
  const { data: session } = useSession();

  return (
    <div>
      <h1>NextAuth.js OAuth Demo</h1>
      {session ? (
        <div>
          <p>Welcome, {session.user.name}</p>
          <button onClick={() => signOut()}>Sign Out</button>
        </div>
      ) : (
        <button onClick={() => signIn()}>Sign In</button>
      )}
    </div>
  );
}

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

  • ใช้ useSession() เช็กสถานะล็อกอิน
  • ถ้าล็อกอินแล้ว แสดงชื่อและปุ่ม Sign Out
  • ถ้ายังไม่ล็อกอิน แสดงปุ่ม Sign In


🚀 ทดสอบการล็อกอิน

    รันเซิร์ฟเวอร์:

    npm run dev

    เปิด http://localhost:3000 แล้วลองกด Sign In
    เลือกล็อกอินผ่าน Google, Facebook หรือ GitHub

🎯 สรุป

NextAuth.js ทำให้การเพิ่ม OAuth Login เป็นเรื่องง่ายมาก 🔥
แค่ติดตั้ง, คอนฟิก Providers, สร้าง UI แล้วก็ใช้งานได้เลย!

✅ รองรับหลายแพลตฟอร์ม
✅ ไม่ต้องเขียน Backend เอง
✅ ใช้กับ Next.js ได้แบบ Native

ใครกำลังหาโซลูชัน Authentication สำหรับ Next.js นี่คือทางเลือกที่ดีที่สุด! 🚀

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

การใช้ NextAuth.js สำหรับการล็อกอินในแอป Next.js

ถ้าคุณกำลังพัฒนาเว็บแอปด้วย Next.js แล้วอยากเพิ่มระบบล็อกอินที่ปลอดภัยโดยไม่ต้องปวดหัวกับการจัดการ JWT, OAuth, หรือ Session เอง NextAuth.js คือคำตอบที่คุณต้องการ!

NextAuth.js คืออะไร?

NextAuth.js เป็น authentication library สำหรับ Next.js ที่ทำให้การเพิ่มระบบล็อกอินเป็นเรื่องง่าย รองรับหลาย ๆ provider เช่น Google, Facebook, GitHub, Twitter หรือแม้กระทั่ง credentials-based login (อีเมล/รหัสผ่าน)

จุดเด่นของ NextAuth.js คือ ไม่ต้องเขียน backend เอง เพราะมันใช้ API routes ของ Next.js จัดการ authentication ให้เสร็จสรรพ

ติดตั้ง NextAuth.js

ก่อนอื่น ไปที่โปรเจกต์ Next.js ของคุณ แล้วติดตั้ง NextAuth.js ด้วยคำสั่งนี้:

npm install next-auth
# หรือใช้ yarn
yarn add next-auth

ตั้งค่า NextAuth.js

NextAuth ต้องใช้ API Route ในการจัดการ authentication ดังนั้นเราจะสร้างไฟล์ pages/api/auth/[...nextauth].js (หรือ .ts ถ้าใช้ TypeScript)

ตัวอย่างการตั้งค่า NextAuth.js

import NextAuth from "next-auth";
import GoogleProvider from "next-auth/providers/google";

export default NextAuth({
  providers: [
    GoogleProvider({
      clientId: process.env.GOOGLE_CLIENT_ID,
      clientSecret: process.env.GOOGLE_CLIENT_SECRET,
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
});

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

  • เราใช้ GoogleProvider เป็น provider สำหรับล็อกอินผ่าน Google
  • ค่า clientId และ clientSecret จะถูกเก็บไว้ในไฟล์ .env.local เพื่อความปลอดภัย
  • NEXTAUTH_SECRET เป็นคีย์สำหรับเข้ารหัส session tokens


ตั้งค่า Environment Variables

สร้างไฟล์ .env.local แล้วใส่ค่าต่อไปนี้ (อย่าลืมเปลี่ยนค่าให้ตรงกับของจริงจาก Google API Console)

GOOGLE_CLIENT_ID=your-google-client-id
GOOGLE_CLIENT_SECRET=your-google-client-secret
NEXTAUTH_SECRET=your-random-secret-key

📌 TIP: ใช้คำสั่งนี้ใน Terminal เพื่อสร้างค่า NEXTAUTH_SECRET แบบสุ่ม

openssl rand -base64 32


เพิ่มปุ่มล็อกอิน/ล็อกเอาต์ในหน้าเว็บ

NextAuth.js มี React Hooks ที่ให้เราดึงสถานะล็อกอินของผู้ใช้มาแสดงผลได้ง่าย ๆ

แก้ไข pages/index.js เพื่อเพิ่มปุ่มล็อกอิน

import { signIn, signOut, useSession } from "next-auth/react";

export default function Home() {
  const { data: session } = useSession();

  return (
    <div>
      {session ? (
        <>
          <p>Welcome, {session.user.name}!</p>
          <img src={session.user.image} alt="Profile" width={50} height={50} />
          <button onClick={() => signOut()}>Sign Out</button>
        </>
      ) : (
        <>
          <p>You are not logged in.</p>
          <button onClick={() => signIn("google")}>Sign in with Google</button>
        </>
      )}
    </div>
  );
}

🔹 อธิบายโค้ดนี้:

  • useSession() ใช้ดึงข้อมูล session ของผู้ใช้
  • ถ้าผู้ใช้ล็อกอินอยู่ จะแสดง ชื่อ และ รูปโปรไฟล์
  • ถ้ายังไม่ได้ล็อกอิน จะแสดงปุ่มให้กดล็อกอินผ่าน Google
  • signIn("google") และ signOut() เป็นฟังก์ชันสำหรับล็อกอินและล็อกเอาต์


ปรับแต่ง NextAuth.js

ถ้าคุณต้องการเพิ่ม database หรือเปลี่ยนแปลง behavior ของ NextAuth.js สามารถแก้ไข pages/api/auth/[...nextauth].js ได้ เช่น
ใช้ Credentials Login (อีเมล/รหัสผ่าน)

import NextAuth from "next-auth";
import CredentialsProvider from "next-auth/providers/credentials";

export default NextAuth({
  providers: [
    CredentialsProvider({
      name: "Credentials",
      credentials: {
        email: { label: "Email", type: "email" },
        password: { label: "Password", type: "password" },
      },
      async authorize(credentials) {
        if (credentials.email === "test@example.com" && credentials.password === "password123") {
          return { id: 1, name: "Test User", email: credentials.email };
        }
        return null;
      },
    }),
  ],
  secret: process.env.NEXTAUTH_SECRET,
});

💡 สิ่งที่เพิ่มเข้ามา:

  • CredentialsProvider ให้ผู้ใช้ล็อกอินด้วยอีเมล/รหัสผ่าน
  • ฟังก์ชัน authorize(credentials) ใช้ตรวจสอบข้อมูลผู้ใช้
  • ตอนนี้ใช้เงื่อนไขแบบง่าย ๆ (เช็คอีเมลกับรหัสผ่านตรงกัน) แต่ในโปรดักชันควรใช้ database หรือ hashed password


ใช้ Middleware เพื่อป้องกันหน้าเว็บที่ต้องล็อกอิน

ถ้าคุณต้องการป้องกันบางหน้าให้เฉพาะผู้ใช้ที่ล็อกอินแล้วเข้าถึงได้ สามารถใช้ Middleware ของ Next.js

สร้างไฟล์ middleware.js ที่ root ของโปรเจกต์

import { withAuth } from "next-auth/middleware";

export default withAuth({
  pages: {
    signIn: "/",
  },
});

📌 สิ่งที่ทำได้:

  • ถ้าผู้ใช้ไม่ได้ล็อกอิน จะถูก redirect ไปที่หน้า /
  • ใช้กับ server-side protection ได้ โดยใส่ใน API Routes


สรุป

✅ ติดตั้ง NextAuth.js และเพิ่ม API Route
✅ ตั้งค่า Google OAuth หรือใช้ Credentials Login
✅ เพิ่มปุ่มล็อกอิน/ล็อกเอาต์ ในหน้าเว็บ
✅ ใช้ Middleware เพื่อป้องกันหน้าที่ต้องล็อกอิน

NextAuth.js ทำให้การเพิ่มระบบล็อกอินใน Next.js ง่ายขึ้นมาก! ถ้าคุณต้องการระบบล็อกอินที่ ปลอดภัย, ยืดหยุ่น, และขยายต่อได้ง่าย NextAuth.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 เป็นไปอย่างราบรื่นและปลอดภัย

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

การใช้ Supabase กับ Next.js

ทำไมต้อง Supabase?

ถ้าพูดถึงการทำแอปเว็บที่ต้องมีฐานข้อมูล การสมัครสมาชิก หรือ API แบบง่าย ๆ แต่ทรงพลัง Supabase นี่แหละคือของดีที่ควรลอง เพราะมันให้บริการ Backend-as-a-Service (BaaS) ที่ทำงานคล้าย Firebase แต่ใช้ PostgreSQL เป็นฐานข้อมูลหลัก ซึ่งหมายความว่าได้ทั้ง SQL แท้ ๆ และพลังของ Firebase มารวมกัน!

จุดเด่นของ Supabase:

  • ฐานข้อมูล PostgreSQL แบบ Managed (ไม่ต้องตั้งค่าจุกจิก)
  • Authentication ที่รองรับ OAuth, Email/Password และ Magic Links
  • Realtime Database สามารถ Subscriptions เหมือน Firebase
  • Storage สำหรับเก็บไฟล์ เช่น รูปหรือวิดีโอ
  • Edge Functions สำหรับสร้าง API แบบ Serverless
  • ใช้งานฟรีในระดับเริ่มต้น!


ทำไม Next.js ถึงเป็นตัวเลือกที่ดี?

ถ้า Supabase เป็นขุมพลังฝั่ง Backend งั้นฝั่ง Frontend ที่มาเข้าคู่กันได้ดีสุดก็คือ Next.js นี่แหละ ด้วยความสามารถแบบ Full-Stack ที่ให้เราสร้าง API Routes, Server-side Rendering (SSR), Static Site Generation (SSG) และ Client-side Rendering (CSR) ได้ในโปรเจกต์เดียวกัน ทำให้สามารถใช้ Supabase ได้เต็มประสิทธิภาพสุด ๆ

มาเริ่มใช้ Supabase กับ Next.js กันเถอะ!

1. สร้างโปรเจกต์ Next.js

เริ่มจากการสร้างโปรเจกต์ Next.js กันก่อน ใช้คำสั่งนี้ใน Terminal:

npx create-next-app@latest my-supabase-app
cd my-supabase-app
npm install

2. ติดตั้ง Supabase SDK

เมื่อมีโปรเจกต์ Next.js แล้ว เราต้องเพิ่ม Supabase SDK เข้าไป:

npm install @supabase/supabase-js

3. ตั้งค่า Supabase Client

Supabase ต้องการ API URL และ Anon Key ซึ่งเราจะได้มาจาก supabase.com หลังจากสมัครและสร้างโปรเจกต์ใหม่

ให้สร้างไฟล์ .env.local แล้วใส่ค่าแบบนี้:

NEXT_PUBLIC_SUPABASE_URL=your-supabase-url
NEXT_PUBLIC_SUPABASE_ANON_KEY=your-anon-key

จากนั้นสร้าง utils/supabaseClient.js เพื่อเชื่อมต่อ Supabase:

import { createClient } from '@supabase/supabase-js';

const supabaseUrl = process.env.NEXT_PUBLIC_SUPABASE_URL;
const supabaseAnonKey = process.env.NEXT_PUBLIC_SUPABASE_ANON_KEY;

export const supabase = createClient(supabaseUrl, supabaseAnonKey);

4. การสมัครสมาชิกและล็อกอินด้วย Supabase Auth

ใน Next.js เราสามารถใช้ Supabase Auth เพื่อให้ผู้ใช้ สมัครสมาชิก, ล็อกอิน และออกจากระบบ ได้ง่าย ๆ

สมัครสมาชิก

import { supabase } from '../utils/supabaseClient';

async function signUp(email, password) {
  const { user, error } = await supabase.auth.signUp({ email, password });
  if (error) {
    console.error(error.message);
  } else {
    console.log('User signed up:', user);
  }
}

ล็อกอิน

async function signIn(email, password) {
  const { user, error } = await supabase.auth.signInWithPassword({ email, password });
  if (error) {
    console.error(error.message);
  } else {
    console.log('User signed in:', user);
  }
}

ออกจากระบบ

async function signOut() {
  const { error } = await supabase.auth.signOut();
  if (error) {
    console.error(error.message);
  } else {
    console.log('User signed out');
  }
}

5. การใช้ Realtime Database

หนึ่งในจุดแข็งของ Supabase คือ Realtime Database ซึ่งช่วยให้เราติดตามการเปลี่ยนแปลงของข้อมูลได้ทันที

ตัวอย่างการ Subscriptions ตาราง messages:

import { useEffect, useState } from 'react';
import { supabase } from '../utils/supabaseClient';

export default function Chat() {
  const [messages, setMessages] = useState([]);

  useEffect(() => {
    const subscription = supabase
      .channel('messages')
      .on('postgres_changes', { event: '*', schema: 'public', table: 'messages' }, (payload) => {
        setMessages((prevMessages) => [...prevMessages, payload.new]);
      })
      .subscribe();
    return () => {
      supabase.removeChannel(subscription);
    };
  }, []);

  return (
    <div>
      {messages.map((msg, index) => (
        <p key={index}>{msg.content}</p>
      ))}
    </div>
  );
}

6. การใช้ Supabase Storage

ถ้าอยากอัปโหลดไฟล์ภาพไปเก็บไว้บน Supabase ก็ทำได้ง่าย ๆ

async function uploadFile(file) {
  const { data, error } = await supabase.storage.from('avatars').upload(`public/${file.name}`, file);
  if (error) {
    console.error('Upload error:', error.message);
  } else {
    console.log('Uploaded file:', data);
  }
}

7. การสร้าง API ด้วย Supabase Edge Functions

ถ้าต้องการ API แบบ Serverless ก็สามารถใช้ Edge Functions ของ Supabase ได้ โดยเขียนฟังก์ชันใน TypeScript และ Deploy ไปยัง Supabase

import { serve } from 'std/server';
export default serve(async (req) => {
  return new Response('Hello from Supabase Edge Function!');
});

สรุป

Supabase เป็นตัวเลือกที่ยอดเยี่ยมสำหรับการทำ Full-Stack Development กับ Next.js เพราะมันให้เราสร้างแอปพลิเคชันที่มี Authentication, Database, Storage และ Realtime ได้ง่ายมาก ๆ ถ้าคุณกำลังหา Backend ที่ใช้ง่าย แต่ทรงพลัง บอกเลยว่า Supabase คือทางเลือกที่ดี!

วันอังคารที่ 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 ดู แล้วจะรู้ว่ามัน โคตรสะดวก! 🚀

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

การใช้ SWR ใน Next.js เพื่อดึงข้อมูลแบบ Client-side

ในโลกของการพัฒนาเว็บแอปพลิเคชัน ฝั่ง Frontend ต้องมีวิธีดึงข้อมูลจาก API อย่างมีประสิทธิภาพ ซึ่งใน Next.js มีหลายแนวทางให้เลือกใช้ เช่น getServerSideProps (SSR), getStaticProps (SSG), หรือ Client-side Fetching ซึ่งแต่ละวิธีก็มีข้อดีข้อเสียต่างกันไป

ถ้าพูดถึงการดึงข้อมูลแบบ Client-side แล้ว SWR เป็นตัวเลือกที่หลายคนชอบ เพราะมันช่วยให้การ fetch ข้อมูลลื่นไหล อัปเดตอัตโนมัติ และยังจัดการแคชได้อย่างฉลาด วันนี้เราจะมาทำความรู้จัก SWR และดูวิธีใช้งานใน Next.js กันแบบเข้าใจง่าย ๆ

🔍 SWR คืออะไร?

SWR ย่อมาจาก Stale-While-Revalidate เป็นแนวคิดที่ช่วยให้การดึงข้อมูลเร็วและสดใหม่ตลอดเวลา โดยที่ไม่ต้องให้ผู้ใช้รอนานเกินไป โดยถูกพัฒนาโดยทีมเดียวกับ Next.js (Vercel) ทำให้มันเหมาะกับการใช้ในโปรเจ็กต์ที่พัฒนาโดย Next.js มาก

หลักการของ SWR คือ

  • คืนค่าข้อมูลเก่าจากแคชก่อน เพื่อให้ผู้ใช้เห็นข้อมูลเร็วที่สุด
  • ดึงข้อมูลใหม่จาก API อยู่เบื้องหลัง
  • อัปเดตข้อมูลใหม่ ใน UI อัตโนมัติ

ฟังดูดีใช่ไหม? เพราะมันช่วยให้การโหลดข้อมูลไม่กระตุก และมีประสบการณ์ใช้งานที่ดีขึ้น

🚀 ติดตั้ง SWR

ก่อนอื่น ถ้ายังไม่ได้ติดตั้ง SWR สามารถติดตั้งได้ง่าย ๆ ด้วยคำสั่งนี้

npm install swr
# หรือถ้าใช้ yarn
yarn add swr

เสร็จแล้วก็พร้อมลุย! 🎉

🛠 วิธีใช้ SWR เบื้องต้น

SWR ใช้งานง่ายมาก ๆ เพียงแค่ import และใช้ useSWR ใน React Component

import useSWR from 'swr'

const fetcher = (url) => fetch(url).then(res => res.json())

export default function Profile() {
  const { data, error } = useSWR('/api/user', fetcher)

  if (error) return <div>โหลดข้อมูลไม่สำเร็จ 😢</div>
  if (!data) return <div>กำลังโหลดข้อมูล... ⏳</div>

  return (
    <div>
      <h1>สวัสดี, {data.name}!</h1>
      <p>อีเมล: {data.email}</p>
    </div>
  )
}

อธิบายโค้ด

  • เราใช้ useSWR เพื่อดึงข้อมูลจาก /api/user
  • fetcher คือฟังก์ชันที่ใช้ดึงข้อมูลจาก API
  • ถ้ามี error จะแสดงข้อความผิดพลาด
  • ถ้าข้อมูลยังมาไม่ถึง จะแสดงข้อความ กำลังโหลด...
  • ถ้าทุกอย่างเรียบร้อยแล้ว ก็โชว์ข้อมูลที่ดึงมาได้

ข้อดีของวิธีนี้คือ ไม่ต้องใช้ useEffect หรือจัดการ state เองเลย เพราะ SWR จัดการให้หมด!

⚡️ ทำไม SWR ถึงดีกว่า useEffect + fetch?

บางคนอาจสงสัยว่า "แล้วทำไมไม่ใช้ useEffect กับ fetch ตรง ๆ ล่ะ?" คำตอบคือ SWR ดีกว่าเพราะ

✅ จัดการแคชให้อัตโนมัติ – ไม่ต้องโหลดข้อมูลซ้ำถ้ายังอยู่ในแคช
✅ อัปเดตข้อมูลเมื่อมีการเปลี่ยนแปลง – ไม่ต้อง reload หน้าเอง
✅ รองรับการ Revalidate อัตโนมัติ – ดึงข้อมูลใหม่เมื่อลูกค้ากลับมาที่หน้าเว็บ
✅ รองรับการดึงข้อมูลแบบ on-focus & re-fetch on reconnect – ไม่ต้องกดรีเฟรชเอง

ถ้าใช้ useEffect และ fetch เราต้องเขียนโค้ดจัดการแคชเอง ซึ่งยุ่งยากและซับซ้อนกว่า

🔄 ตัวอย่างการใช้ Mutate และ Revalidate

ถ้าต้องการให้ข้อมูลอัปเดตทันทีโดยไม่ต้องรอ SWR รีเฟรชเอง สามารถใช้ mutate ได้

import useSWR, { mutate } from 'swr'

const fetcher = (url) => fetch(url).then(res => res.json())

export default function Dashboard() {
  const { data } = useSWR('/api/stats', fetcher)

  return (
    <div>
      <h1>ยอดผู้ใช้งาน: {data ? data.users : 'กำลังโหลด...'}</h1>
      <button onClick={() => mutate('/api/stats')}>โหลดข้อมูลใหม่</button>
    </div>
  )
}

เมื่อกดปุ่ม โหลดข้อมูลใหม่ ระบบจะดึงข้อมูลใหม่จาก API ทันที

🔐 ใช้ SWR กับ Authentication

SWR เหมาะกับระบบที่ต้องใช้ Token Authentication เช่น JWT หรือ OAuth เพราะสามารถส่ง Header ไปกับทุก Request ได้ง่าย ๆ

import useSWR from 'swr'

const fetcher = (url) =>
  fetch(url, {
    headers: {
      Authorization: `Bearer ${localStorage.getItem('token')}`,
    },
  }).then((res) => res.json())

export default function UserProfile() {
  const { data, error } = useSWR('/api/profile', fetcher)

  if (error) return <div>โหลดข้อมูลไม่สำเร็จ</div>
  if (!data) return <div>กำลังโหลด...</div>

  return <h1>ชื่อผู้ใช้: {data.username}</h1>
}


🔥 การใช้งาน SWR กับ GraphQL

ถ้าใช้ GraphQL เราก็สามารถใช้ SWR ได้ โดยเปลี่ยนจาก fetch เป็นการส่ง Query ไปยัง API

const fetcher = (query) =>
  fetch('/graphql', {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify({ query }),
  }).then((res) => res.json())

const GET_USER = `
  {
    user {
      name
      email
    }
  }
`

export default function UserProfile() {
  const { data, error } = useSWR(GET_USER, fetcher)

  if (error) return <div>โหลดข้อมูลไม่สำเร็จ</div>
  if (!data) return <div>กำลังโหลด...</div>

  return <h1>ชื่อ: {data.user.name}</h1>
}

📌 สรุป

SWR เป็นเครื่องมือที่ช่วยให้การดึงข้อมูลแบบ Client-side ง่ายขึ้น โดยที่ไม่ต้องจัดการแคชเอง รองรับการอัปเดตข้อมูลอัตโนมัติ และมีประสิทธิภาพสูงกว่าการใช้ useEffect + fetch แบบเดิม ๆ
✅ เหมาะกับ

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

ถ้าคุณใช้ Next.js อยู่แล้ว ลองเอา SWR ไปใช้ดู รับรองว่าชีวิตง่ายขึ้นแน่นอน! 🚀

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

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