Sitemap

พื้นฐานการสร้างระบบยืนยันตัวตน (Authentication) ด้วย Next.js, Prisma และ MySQL

5 min readFeb 27, 2025
Press enter or click to view image in full size

Authentication (การยืนยันตัวตน) เป็นกระบวนการตรวจสอบว่า ผู้ใช้ที่เข้าสู่ระบบเป็นบุคคลที่อ้างตัวตนจริงหรือไม่ โดยทั่วไปการยืนยันตัวตนจะทำผ่านการใช้ ชื่อผู้ใช้ (Username) และรหัสผ่าน (Password) หรืออาจมีการใช้ปัจจัยเพิ่มเติม เช่น OTP (One-Time Password) ในบทความนี้แสดงพื้นฐานการสร้างระบบยืนยันตัวตนด้วย Next.js, Prisma และ MySQL

Next.js

Next.js เป็นเฟรมเวิร์กสำหรับพัฒนาเว็บแอปพลิเคชันที่สร้างขึ้นบน React ซึ่งช่วยให้การพัฒนาเว็บทำได้ง่ายขึ้นและมีประสิทธิภาพมากขึ้น

Prisma

Prisma เป็น ORM (Object-Relational Mapping) สำหรับจัดการฐานข้อมูล SQL ในแอปพลิเคชัน Node.js ซึ่งช่วยให้เราสามารถเขียนโค้ดจัดการฐานข้อมูลได้ง่ายขึ้น มีการรองรับ TypeScript และช่วยลดความยุ่งยากในการเขียนคำสั่ง SQL โดยตรง

MySQL

MySQL เป็นระบบจัดการฐานข้อมูลเชิงสัมพันธ์ (Relational Database Management System — RDBMS) ที่นิยมใช้กันอย่างแพร่หลาย เหมาะสำหรับแอปพลิเคชันที่ต้องการความเสถียรและประสิทธิภาพในการจัดเก็บข้อมูล

1. ติดตั้งโปรแกรมที่จำเป็น

ก่อนเริ่มพัฒนา ให้ติดตั้งโปรแกรมต่อไปนี้:

  • XAMPP: สำหรับการรันเซิร์ฟเวอร์ MySQL บนเครื่องของเรา
  • Node.js: ควรติดตั้งเวอร์ชันล่าสุดที่รองรับ Next.js 15
  • Visual Studio Code (VSCode): เครื่องมือสำหรับการพัฒนาโค้ด
  • Postman: เครื่องมือสำหรับทดสอบ API

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

เปิด Terminal หรือ Command Prompt แล้วรันคำสั่ง:

npx create-next-app@15 next-auth-app

โดยเลือกการตั้งค่าของโปรเจคตามนี้ได้:

Press enter or click to view image in full size

จากนั้นเข้าไปในโฟลเดอร์โปรเจค:

cd next-auth-app

ติดตั้งไลบรารีที่จำเป็น:

npm install prisma @prisma/client bcryptjs

3. ตั้งค่า Prisma กับ MySQL

สร้างฐานข้อมูล next_auth_db ใน MySQL ด้วย phpMyAdmin http://localhost/phpmyadmin/

Press enter or click to view image in full size

สร้างไฟล์ .env และกำหนดค่าการเชื่อมต่อ MySQL:

DATABASE_URL="mysql://root:@localhost:3306/next_auth_db"

จากนั้นรันคำสั่งเพื่อสร้าง Prisma Schema:

npx prisma init

แก้ไขไฟล์ prisma/schema.prisma ให้กำหนดโครงสร้างของตาราง User:

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

จากนั้นรันคำสั่งเพื่อสร้างฐานข้อมูล (ถ้ายังไม่ได้สร้าง) และตาราง user:

npx prisma migrate dev - name init

ตรวจสอบตาราง User ที่ถูกสร้างในฐานข้อมูล next_auth_db จากโปรแกรม phpMyAdmin

Press enter or click to view image in full size

4. รันโปรเจค

สร้างไลบรารีไคลเอนต์ของ Prisma เพื่อใช้งานกับฐานข้อมูล

npx prisma generate

รันโปรเจค

npm run dev
Press enter or click to view image in full size

ทดสอบโปรเจคโดยการเข้าผ่าน http://localhost:3000/

Press enter or click to view image in full size

5. สร้าง API สำหรับ Authentication

การเชื่อมต่อ Prisma

สร้างไฟล์ lib/prisma.js เพื่อจัดการการเชื่อมต่อกับฐานข้อมูล:

import { PrismaClient } from '@prisma/client';
const prisma = new PrismaClient();
export default prisma;

API สำหรับ Login

สร้างไฟล์ app/api/auth/login/route.js ซึ่งใช้รับข้อมูลการเข้าสู่ระบบและตรวจสอบความถูกต้อง:

import { NextResponse } from 'next/server';
import bcrypt from 'bcryptjs';
import prisma from '@/lib/prisma';

export async function POST(req) {
const { email, password } = await req.json();
const user = await prisma.user.findUnique({ where: { email } });

if (!user) {
return NextResponse.json({ error: 'User not found' }, { status: 404 });
}

const validPassword = await bcrypt.compare(password, user.password);
if (!validPassword) {
return NextResponse.json({ error: 'Invalid password' }, { status: 401 });
}

return NextResponse.json({ message: 'Login successful', user });
}

API สำหรับ Signup

สร้างไฟล์ app/api/auth/signup/route.js เพื่อรับข้อมูลการลงทะเบียนและสร้างบัญชีใหม่:

import { NextResponse } from 'next/server';
import bcrypt from 'bcryptjs';
import prisma from '@/lib/prisma';

export async function POST(req) {
const { email, password } = await req.json();
const existingUser = await prisma.user.findUnique({ where: { email } });

if (existingUser) {
return NextResponse.json({ error: 'Email already in use' }, { status: 400 });
}

const hashedPassword = await bcrypt.hash(password, 10);

await prisma.user.create({
data: { email, password: hashedPassword },
});

return NextResponse.json({ message: 'User registered successfully' });
}

6. ทดสอบ API ด้วย Postman

ทดสอบ Signup API
สร้าง Request ด้วยข้อมูลดังต่อไปนี้
POST http://localhost:3000/api/auth/signup
Body (JSON):

{
"email": "test@example.com",
"password": "1234"
}

ผลลัพธ์ที่คาดว่าจะได้

{
"message": "User registered successfully"
}
Press enter or click to view image in full size

ทดสอบ Login API
สร้าง Request ด้วยข้อมูลดังต่อไปนี้
POST http://localhost:3000/api/auth/login
Body (JSON):

{
"email": "test@example.com",
"password": "1234"
}

ผลลัพธ์ที่คาดว่าจะได้

{
"message": "Login successful",
"user": {
"id": 3,
"email": "test@example.com",
"password": "$2b$10$1Y4EHExRDxn2/ay2pQo/7eDUBiQVABnr3sek6CndBPTRqrzLMsCTK"
}
}
Press enter or click to view image in full size

7. สร้างหน้าเว็บ

แก้ไข globals.css

แก้ไขไฟล์ app/globals.css ที่มาพร้อมกับโปรเจค

@tailwind base;
@tailwind components;
@tailwind utilities;

สร้างหน้าเว็บสำหรับ Signup

สร้างไฟล์ app/signup/page.js สำหรับการลงทะเบียนและสร้างบัญชีใหม่:

"use client";

import { useState } from "react";
import { useRouter } from "next/navigation";

export default function SignupPage() {
const router = useRouter();
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [success, setSuccess] = useState(false);

const handleSignup = async (e) => {
e.preventDefault();
setError("");
setSuccess(false);

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

if (!res.ok) {
const data = await res.json();
setError(data.error);
return;
}

setSuccess(true);
};

return (
<div className="flex justify-center items-center min-h-screen bg-gray-100">
{success ? (
<div className="bg-white p-6 rounded-lg shadow-md w-96 text-center">
<h2 className="text-2xl font-bold mb-4 text-green-500">Signup Successful!</h2>
<p className="mb-4">You have successfully created an account.</p>
<button
onClick={() => router.push("/login")}
className="w-full bg-blue-500 text-white p-2 rounded"
>
Go to Login
</button>
</div>
) : (
<form onSubmit={handleSignup} className="bg-white p-6 rounded-lg shadow-md w-96">
<h2 className="text-2xl font-bold mb-4">Sign Up</h2>
{error && <p className="text-red-500">{error}</p>}
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full p-2 border rounded mb-2"
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full p-2 border rounded mb-4"
/>
<button className="w-full bg-green-500 text-white p-2 rounded">Sign Up</button>
</form>
)}
</div>
);
}

ทดสอบการลงทะเบียนผ่านหน้าเว็บ http://localhost:3000/signup

Press enter or click to view image in full size
Press enter or click to view image in full size

สร้างหน้าเว็บสำหรับ Login

สร้างไฟล์ app/signup/login.js สำหรับการยืนยันตัวตนเข้าใช้งานระบบ:

"use client";

import { useState } from "react";

export default function LoginPage() {
const [email, setEmail] = useState("");
const [password, setPassword] = useState("");
const [error, setError] = useState("");
const [success, setSuccess] = useState("");

const handleLogin = async (e) => {
e.preventDefault();
setError("");
setSuccess("");

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

if (!res.ok) {
const data = await res.json();
setError(data.error);
return;
}

const data = await res.json();
setSuccess(`Successfully logged in as ${data.user.email}`);
};

return (
<div className="flex justify-center items-center min-h-screen bg-gray-100">

{success ? (
<p className="text-green-500">{success}</p>
) : (
<form onSubmit={handleLogin} className="bg-white p-6 rounded-lg shadow-md w-96">
<h2 className="text-2xl font-bold mb-4">Login</h2>
{error && <p className="text-red-500">{error}</p>}
<input
type="email"
placeholder="Email"
value={email}
onChange={(e) => setEmail(e.target.value)}
className="w-full p-2 border rounded mb-2"
/>
<input
type="password"
placeholder="Password"
value={password}
onChange={(e) => setPassword(e.target.value)}
className="w-full p-2 border rounded mb-4"
/>
<button className="w-full bg-blue-500 text-white p-2 rounded">Login</button>
</form>
)}
</div>
);
}

ทดสอบการยืนยันตัวตนผ่านหน้าเว็บ http://localhost:3000/login

Press enter or click to view image in full size
Press enter or click to view image in full size

จบแล้วนะครับการพื้นฐานการสร้างระบบยืนยันตัวตนด้วย Next.js, Prisma และ MySQL โดยถ้ามีโอกาสในเนื้อหาถัดไปจะพูดถึง protected page หรือหน้าเว็บที่สามารถเข้าถึงได้เฉพาะผู้ที่ยืนยันตัวเรียบร้อยแล้ว โดยการใช้ JWT (JSON Web Token) พบกันใหม่โอกาสหน้า สวัสดีครับ

บทความโดย อ.ผศ.ดร.กานต์ ยงศิริวิทย์
วิทยาลัยนวัตกรรมดิจิทัลเทคโนโลยี มหาวิทยาลัยรังสิต
Youtube: https://youtube.com/@melivecode
Facebook: https://facebook.com/melivecodepage
Tiktok: https://tiktok.com/@melivecode
Instagram: https://instagram.com/melivecode
Medium: https://karnyong.medium.com
Twitter: https://twitter.com/melivecode
Discord: https://discord.gg/PcvymzR7HD
Free API: https://www.melivecode.com

--

--

Karn Yongsiriwit
Karn Yongsiriwit

Written by Karn Yongsiriwit

Lecturer at Digital Innovation Technology, Rangsit University

No responses yet