dev-resources.site
for different kinds of informations.
วิธีทำ Auth API ด้วย Express, JWT, MySQL และ Prisma
Published at
12/24/2024
Categories
express
mysql
prisma
jwt
Author
xnewz
Author
5 person written this
xnewz
open
การสร้าง Auth API ด้วย JWT และ MySQL โดยใช้ Prisma สำหรับการจัดการฐานข้อมูล
จะมีการแยกส่วนประกอบออกเป็นไฟล์ต่างๆ เพื่อความสะดวกในการแก้ไข
โดยในตัวอย่างนี้ เราจะใช้ Node.js กับ Express.js สำหรับ backend และ JWT สำหรับการจัดการ token
พร้อมด้วย Prisma สำหรับการจัดการกับฐานข้อมูล MySQL
ขั้นตอนการติดตั้งและตั้งค่า
mkdir auth-api
cd auth-api
สร้างโปรเจค Node.js และติดตั้ง package ที่ใช้
npm init -y
npm install express prisma @prisma/client jsonwebtoken bcryptjs body-parser
ตั้งค่า Prisma
npx prisma init
ตั้งค่าไฟล์ Prisma schema
- prisma/schema.prisma
generator client {
provider = "prisma-client-js"
}
datasource db {
provider = "mysql"
url = env("DATABASE_URL")
}
model User {
id Int @id @default(autoincrement())
username String @unique
password String
}
ตั้งค่าไฟล์ .env
-
user
ชื่อผู้ใช้ของ MySQL -
password
รหัสผ่านของ MySQL -
localhost:3306
ที่อยู่ของ MySQL -
auth_db
ชื่อฐานข้อมูลที่จะใช้
DATABASE_URL="mysql://user:password@localhost:3306/auth_db"
สร้างฐานข้อมูลและตาราง
npx prisma migrate dev --name init
สร้างไฟล์และโฟลเดอร์ต่างๆ
touch server.js config.js routes.js
mkdir controllers models middlewares
touch controllers/authController.js middlewares/middleware.js
โครงสร้างโปรเจค
auth-api/
├── controllers/
│ └── authController.js
├── middlewares/
│ └── middleware.js
├── models/
│ └── userModel.js
├── prisma/
│ ├── migrations/
│ │ └── <migration files>
│ ├── schema.prisma
├── .env
├── config.js
├── package.json
├── routes.js
├── server.js
เขียนโค้ดสำหรับแต่ละไฟล์
- server.js
const express = require('express'); // เรียกใช้งาน express เพื่อสร้าง server
const bodyParser = require('body-parser'); // เรียกใช้งาน body-parser เพื่อแปลงข้อมูลที่ส่งมาให้เป็น JSON
const routes = require('./routes'); // เรียกใช้งานไฟล์ routes.js ที่เราสร้างไว้เพื่อใช้ในการกำหนดเส้นทางของ API
const app = express(); // สร้าง instance ของ express
const PORT = process.env.PORT || 3000; // กำหนด port ที่จะใช้ในการรัน server
app.use(bodyParser.json()); // ใช้ body-parser ในการแปลงข้อมูลที่ส่งมาให้เป็น JSON
app.use('/api', routes); // กำหนดเส้นทางของ API
app.listen(PORT, () => { // รัน server ที่ port ที่กำหนด
console.log(`Server is running on port ${PORT}`);
});
- config.js
module.exports = {
jwtSecret: 'your-secret-key' // กำหนด secret key สำหรับการสร้าง token
};
- models/userModel.js
const { PrismaClient } = require('@prisma/client'); // เรียกใช้งาน PrismaClient จาก @prisma/client
const prisma = new PrismaClient(); // สร้าง instance ของ PrismaClient
const bcrypt = require('bcryptjs'); // เรียกใช้งาน bcryptjs เพื่อใช้ในการเข้ารหัสรหัสผ่าน
// สร้างผู้ใช้ใหม่
const createUser = async (user) => {
// เข้ารหัสรหัสผ่านก่อนที่จะเก็บไว้ในฐานข้อมูล
const hash = await bcrypt.hash(user.password, 10);
// บันทึกข้อมูลผู้ใช้ลงในฐานข้อมูล
return prisma.user.create({
data: {
username: user.username,
password: hash
}
});
};
// ค้นหาผู้ใช้จากชื่อผู้ใช้
const findUserByUsername = async (username) => {
return prisma.user.findUnique({
where: { username: username }
});
};
module.exports = {
createUser,
findUserByUsername
};
- controllers/authController.js
const jwt = require('jsonwebtoken'); // เรียกใช้งาน jwt เพื่อใช้ในการสร้าง token
const bcrypt = require('bcryptjs'); // เรียกใช้งาน bcryptjs เพื่อใช้ในการเข้ารหัสรหัสผ่าน
const config = require('../config'); // เรียกใช้งานไฟล์ config.js ที่เราสร้างไว้
const User = require('../models/userModel'); // เรียกใช้งาน userModel.js ที่เราสร้างไว้
const register = async (req, res) => {
const { username, password } = req.body; // รับข้อมูล username และ password จาก body ของ request
// สร้างผู้ใช้ใหม่
try {
await User.createUser({ username, password });
res.status(201).json({ message: 'User registered successfully' });
} catch (err) { // หากเกิดข้อผิดพลาดในการสร้างผู้ใช้
res.status(500).json({ message: 'Error registering user' });
}
};
const login = async (req, res) => {
const { username, password } = req.body; // รับข้อมูล username และ password จาก body ของ request
try {
const user = await User.findUserByUsername(username); // ค้นหาผู้ใช้จากชื่อผู้ใช้
if (!user) { // หากไม่พบผู้ใช้
return res.status(401).json({ message: 'Invalid username or password' });
}
// หากรหัสผ่านไม่ตรงกับที่เก็บไว้ในฐานข้อมูล
const isMatch = await bcrypt.compare(password, user.password);
if (!isMatch) {
return res.status(401).json({ message: 'Invalid username or password' });
}
// สร้าง token และส่งกลับไปให้ผู้ใช้
const token = jwt.sign({ id: user.id }, config.jwtSecret, { expiresIn: '1h' });
res.json({ token });
} catch (err) { // หากเกิดข้อผิดพลาดในการเข้าสู่ระบบ
res.status(500).json({ message: 'Error logging in' });
}
};
module.exports = {
register,
login
};
- middlewares/middleware.js
const jwt = require('jsonwebtoken'); // เรียกใช้งาน jwt เพื่อใช้ในการตรวจสอบ token
const config = require('../config'); // เรียกใช้งานไฟล์ config.js ที่เราสร้างไว้
// next คือ callback function ที่ใช้ในการส่งต่อไปยัง middleware ถัดไป
const verifyToken = (req, res, next) => { // middleware สำหรับตรวจสอบ token
const token = req.headers['authorization']; // รับ token จาก header ของ request
if (!token) return res.status(403).json({ message: 'No token provided' }); // หากไม่มี token ให้ส่งข้อความกลับไปว่าไม่มี token
jwt.verify(token, config.jwtSecret, (err, decoded) => { // ตรวจสอบ token
if (err) return res.status(500).json({ message: 'Failed to authenticate token' }); // หากไม่สามารถตรวจสอบ token ได้ให้ส่งข้อความกลับไปว่าไม่สามารถตรวจสอบ token ได้
req.userId = decoded.id; // ถ้าตรวจสอบ token สำเร็จ ให้เก็บ id ของผู้ใช้ไว้ใน req.userId
next(); // ส่งต่อไปยัง middleware ถัดไป
});
};
module.exports = {
verifyToken
};
- routes.js
const express = require('express'); // เรียกใช้งาน express
const authController = require('./controllers/authController'); // เรียกใช้งาน authController.js ที่เราสร้างไว้
const middleware = require('./middlewares/middleware'); // เรียกใช้งาน middleware.js ที่เราสร้างไว้
const router = express.Router(); // สร้าง instance ของ express.Router
router.post('/register', authController.register); // สร้างเส้นทางสำหรับการลงทะเบียนผู้ใช้
router.post('/login', authController.login); // สร้างเส้นทางสำหรับการเข้าสู่ระบบ
// Protected route example
router.get('/protected', middleware.verifyToken, (req, res) => { // สร้างเส้นทางสำหรับการตรวจสอบ token
res.json({ message: 'This is a protected route', userId: req.userId }); // ส่งข้อความกลับไปว่านี่คือเส้นทางที่ถูกป้องกัน
});
module.exports = router;
รัน server
node server.js
เราสามารถทดสอบ API ด้วย Postman หรือ Thunder Client โดยการสร้าง request ไปที่ http://localhost:3000/api/register
และ http://localhost:3000/api/login
และส่งข้อมูล username และ password ไปด้วย
ตัวอย่าง request สำหรับ route register
- /api/register
{
"username": "john_doe",
"password": "password123"
}
- Response
{
"message": "User registered successfully"
}
ตัวอย่าง request สำหรับ route login
- /api/login
{
"username": "john_doe",
"password": "password123"
}
- Response
{
"token": "token-string"
}
ตัวอย่าง request สำหรับ route protected
- /api/protected
// ใส่ token ใน header ของ request
{
"Authorization": "token-string"
}
- Response
{
"message": "This is a protected route",
"userId": 1
}
นอกจากนี้เรายังสามารถใช้งาน Prisma Studio เพื่อดูข้อมูลในฐานข้อมูลได้ด้วย
npx prisma studio
สามารถดูตัวอย่างโค้ดทั้งหมดได้จาก GitHub
หรือสามารถดูตัวอย่างการทำงานได้จาก YouTube
prisma Article's
30 articles in total
How to Fix the “Record to Delete Does Not Exist” Error in Prisma
read article
Building Type-Safe APIs: Integrating NestJS with Prisma and TypeScript
read article
Deploying an Existing Express API + Prisma + Supabase Project to Vercel
read article
Exploring the Power of Full-Stack Development with Next.js and Prisma
read article
How to integrate GitHub CopilotKit with Prisma Integration into your nextJs project Using OpenAI
read article
วิธีทำ Auth API ด้วย Express, JWT, MySQL และ Prisma
currently reading
Prisma
read article
How we built "Space-Ease" using Next.js
read article
Query Objects Instead of Repositories: A Modern Approach to Data Access
read article
Common Data Loss Scenarios & Solutions in Prisma Schema Changes
read article
How I Solved Common Prisma ORM Errors: Debugging Tips and Best Practices
read article
Prisma 101 baby.
read article
Prisma
read article
QueryBuilder in Action Part 1
read article
Prisma ORM: Revolutionizing Database Interactions
read article
Prisma & MongoDB: server to be run as a replica set
read article
Using GenAI to Tackle Complex Prisma Model Migrations
read article
When Embedded AuthN Meets Embedded AuthZ - Building Multi-Tenant Apps With Better-Auth and ZenStack
read article
Building Multi-Tenant Apps Using StackAuth's "Teams" and Next.js
read article
The Most Awaited Prisma Course Is Here! 😍
read article
**Building a Full-Stack Next.js Starter Kit: Authentication, GraphQL, and Testing**
read article
Integrate DAYTONA and let the magic begin....
read article
Cloudflare D1 and Prisma: Not a Good Combination (For Now)
read article
Resolving the `DO $$` Issue in Drizzle ORM with Nile Postgres
read article
Nuxt Authorization: How to Implement Team Role-Based Access Control in Nuxt 3
read article
Getting Started with Prisma, SQLite, and Express
read article
Senior Developer Advocate
read article
Building Multi-Tenant Apps Using Clerk's "Organization" and Next.js
read article
How to use ORMs (Prisma / Drizzle / Knex.js) in a TypeScript backend built with Encore.ts
read article
Pagination and Sorting with Prisma in TypeScript
read article
Featured ones: