This post is also available in:
English
Hallo apa kabar teman semua, kambali lagi bersama Teman Ngoding. Pembahasan kali ini kita akan membuat REST API Login dan Register menggunakan Node.js dengan JWT. Dan saya akan memebrikan beberapa contoh untuk membuat Rest API.
Kalian dapat mempelajari tutorial yang lainnya:
Format Number Otomatis Dengan JavaScript Semua Negara
Tutorial Javascript: Convert waktu am pm to 24 Jam
Registrasi dan login adalah modul umum di web atau aplikasi apa pun. Ketika pengguna mendaftar di web dan aplikasi Anda, maka Anda menyimpan datanya di database Anda. Sehingga jika nanti dia ingin login, dia tidak perlu mendaftar lagi. Dalam tutorial ini, Anda akan belajar cara membuat rest API pendaftaran pengguna dengan node js + express + MySQL + JWT auth.
1. Create Node.js Express Login App
Langkah pertama kalian harus buat project baru.
$ mkdir api
$ cd api
Kemudian kita menginisialisasi Aplikasi Node.js dengan file package.json:

Selanjutnya kita perlu install beberapa library: express
, cors
, cookie, session
, sequelize
, mysql2
, jsonwebtoken
and bcryptjs
.
Jalankan perintah ini di commend:
npm install express cookie-session sequelize mysql2 cors jsonwebtoken bcryptjs --save
dan kita dapat melihat package.json kita:
{
"name": "api",
"version": "1.0.0",
"description": "",
"main": "index.js",
"scripts": {
"test": "echo \"Error: no test specified\" && exit 1"
},
"author": "",
"license": "ISC",
"dependencies": {
"bcryptjs": "^2.4.3",
"cookie-session": "^2.0.0",
"cors": "^2.8.5",
"express": "^4.18.1",
"jsonwebtoken": "^8.5.1",
"mysql2": "^2.3.3",
"sequelize": "^6.21.3"
}
}
2. Setup Express web server
di dalam folder root kita, buatlah sebuah file baru server.js file:
Mari saya jelaskan apa yang baru saja kita lakukan:
– impor express, sesi cookie dan modul cors:
Express adalah untuk membangun REST API
cookie-session membantu menyimpan data sesi pada klien di dalam cookie tanpa memerlukan database/sumber daya apa pun di sisi server
cors menyediakan middleware Express untuk mengaktifkan CORS
– buat aplikasi Express, lalu tambahkan parsing permintaan, middleware sesi berbasis cookie, dan middleware cors menggunakan metode app.use().
– tentukan rute GET yang sederhana untuk pengujian.
– dengarkan pada port 8080 untuk permintaan yang masuk.
Sekarang jalankan pertintah ini di commend: node server.js
Buka http://localhost:8080/ di browser kalian, maka kita akan mendapatkan json seperti ini:

3. Konfigurasi MySQL & Sequalize
buatlah folder config dengan file db.config.js, dan tuliskan kode di bawah ini:
module.exports = {
HOST: "localhost",
USER: "root",
PASSWORD: "123456",
DB: "testdb",
dialect: "mysql",
pool: {
max: 5,
min: 0,
acquire: 30000,
idle: 10000
}
};
Lima parameter pertama adalah untuk koneksi MySQL.
pool bersifat opsional, ini akan digunakan untuk konfigurasi Sequelize connection pool:
- max: jumlah maksimum koneksi di pool
- min: jumlah minimum koneksi di pool
- idle: waktu maksimum, dalam milidetik, koneksi dapat idle sebelum dilepaskan
- memperoleh: waktu maksimum, dalam milidetik, kumpulan itu akan mencoba mendapatkan koneksi sebelum melempar kesalahan
4. Define the Sequelize Model
Kita tentukan untuk model sequalize. Di dalam folder models, buat data model user dan role, buatlah kode sebagai berikut:
models/user.model.js
module.exports = (sequelize, Sequelize) => {
const User = sequelize.define("users", {
username: {
type: Sequelize.STRING
},
email: {
type: Sequelize.STRING
},
password: {
type: Sequelize.STRING
}
});
return User;
};
models/role.model.js
module.exports = (sequelize, Sequelize) => {
const Role = sequelize.define("roles", {
id: {
type: Sequelize.INTEGER,
primaryKey: true
},
name: {
type: Sequelize.STRING
}
});
return Role;
};
Setelah menginisialisasi Sequelize, kita tidak perlu menulis fungsi CRUD, Sequelize mendukung semuanya:
- buat Pengguna baru: create(object)
- temukan Pengguna dengan id: findByPk(id)
- temukan Pengguna melalui email: findOne({ where: { email: … } })
- dapatkan semua Pengguna: findAll()
- temukan semua Pengguna berdasarkan nama pengguna: findAll({ where: { username: … } })
5. Initialize Sequelize
Sekarang buat file app/models/index.js dengan kode sebagai berikut:
const config = require("../config/db.config.js");
const Sequelize = require("sequelize");
const sequelize = new Sequelize(
config.DB,
config.USER,
config.PASSWORD,
{
host: config.HOST,
dialect: config.dialect,
operatorsAliases: false,
pool: {
max: config.pool.max,
min: config.pool.min,
acquire: config.pool.acquire,
idle: config.pool.idle
}
}
);
const db = {};
db.Sequelize = Sequelize;
db.sequelize = sequelize;
db.user = require("../models/user.model.js")(sequelize, Sequelize);
db.role = require("../models/role.model.js")(sequelize, Sequelize);
db.role.belongsToMany(db.user, {
through: "user_roles",
foreignKey: "roleId",
otherKey: "userId"
});
db.user.belongsToMany(db.role, {
through: "user_roles",
foreignKey: "userId",
otherKey: "roleId"
});
db.ROLES = ["user", "admin", "moderator"];
module.exports = db;
Hubungan antara Pengguna dan Peran adalah hubungan Banyak-ke-Banyak:
– Satu Pengguna dapat memiliki beberapa Peran.
– Satu Peran dapat diambil oleh banyak Pengguna.
dan jangan lupa untuk memanggil sync() method di server.js.
...
const app = express();
app.use(...);
const db = require("./app/models");
const Role = db.role;
db.sequelize.sync({force: true}).then(() => {
console.log('Drop and Resync Db');
initial();
});
...
function initial() {
Role.create({
id: 1,
name: "user"
});
Role.create({
id: 2,
name: "moderator"
});
Role.create({
id: 3,
name: "admin"
});
}
fungsi initial() membantu kita membuat 3 baris dalam database. Dalam pengembangan, Anda mungkin perlu menghapus tabel yang ada dan menyinkronkan ulang database. Jadi Anda bisa menggunakan force: true seperti kode di atas.
Untuk produksi, cukup masukkan baris ini secara manual dan gunakan sync() tanpa parameter untuk menghindari hilangnya data:
...
const app = express();
app.use(...);
const db = require("./app/models");
db.sequelize.sync();
...
6. Kunfigurasi Auth Key
Fungsi jsonwebtoken seperti verifikasi() atau tanda() menggunakan algoritma yang membutuhkan kunci rahasia (sebagai String) untuk mengkodekan dan mendekode token.
Di folder app/config, buat file auth.config.js dengan kode berikut:
7. Create Middleware functions
middleware/verifySignUp.js
const db = require("../models");
const ROLES = db.ROLES;
const User = db.user;
checkDuplicateUsernameOrEmail = async (req, res, next) => {
try {
// Username
let user = await User.findOne({
where: {
username: req.body.username
}
});
if (user) {
return res.status(400).send({
message: "Failed! Username is already in use!"
});
}
// Email
user = await User.findOne({
where: {
email: req.body.email
}
});
if (user) {
return res.status(400).send({
message: "Failed! Email is already in use!"
});
}
next();
} catch (error) {
return res.status(500).send({
message: "Unable to validate Username!"
});
}
};
checkRolesExisted = (req, res, next) => {
if (req.body.roles) {
for (let i = 0; i < req.body.roles.length; i++) {
if (!ROLES.includes(req.body.roles[i])) {
res.status(400).send({
message: "Failed! Role does not exist = " + req.body.roles[i]
});
return;
}
}
}
next();
};
const verifySignUp = {
checkDuplicateUsernameOrEmail,
checkRolesExisted
};
module.exports = verifySignUp;
middleware/authJwt.js
const jwt = require("jsonwebtoken");
const config = require("../config/auth.config.js");
const db = require("../models");
const User = db.user;
verifyToken = (req, res, next) => {
let token = req.session.token;
if (!token) {
return res.status(403).send({
message: "No token provided!",
});
}
jwt.verify(token, config.secret, (err, decoded) => {
if (err) {
return res.status(401).send({
message: "Unauthorized!",
});
}
req.userId = decoded.id;
next();
});
};
isAdmin = async (req, res, next) => {
try {
const user = await User.findByPk(req.userId);
const roles = await user.getRoles();
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "admin") {
return next();
}
}
return res.status(403).send({
message: "Require Admin Role!",
});
} catch (error) {
return res.status(500).send({
message: "Unable to validate User role!",
});
}
};
isModerator = async (req, res, next) => {
try {
const user = await User.findByPk(req.userId);
const roles = await user.getRoles();
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "moderator") {
return next();
}
}
return res.status(403).send({
message: "Require Moderator Role!",
});
} catch (error) {
return res.status(500).send({
message: "Unable to validate Moderator role!",
});
}
};
isModeratorOrAdmin = async (req, res, next) => {
try {
const user = await User.findByPk(req.userId);
const roles = await user.getRoles();
for (let i = 0; i < roles.length; i++) {
if (roles[i].name === "moderator") {
return next();
}
if (roles[i].name === "admin") {
return next();
}
}
return res.status(403).send({
message: "Require Moderator or Admin Role!",
});
} catch (error) {
return res.status(500).send({
message: "Unable to validate Moderator or Admin role!",
});
}
};
const authJwt = {
verifyToken,
isAdmin,
isModerator,
isModeratorOrAdmin,
};
module.exports = authJwt;
middleware/index.js
const authJwt = require("./authJwt");
const verifySignUp = require("./verifySignUp");
module.exports = {
authJwt,
verifySignUp
};
8. Create Controller
controllers/auth.controller.js
onst db = require("../models");
const config = require("../config/auth.config");
const User = db.user;
const Role = db.role;
const Op = db.Sequelize.Op;
const jwt = require("jsonwebtoken");
const bcrypt = require("bcryptjs");
exports.signup = async (req, res) => {
// Save User to Database
try {
const user = await User.create({
username: req.body.username,
email: req.body.email,
password: bcrypt.hashSync(req.body.password, 8),
});
if (req.body.roles) {
const roles = await Role.findAll({
where: {
name: {
[Op.or]: req.body.roles,
},
},
});
const result = user.setRoles(roles);
if (result) res.send({ message: "User registered successfully!" });
} else {
// user has role = 1
const result = user.setRoles([1]);
if (result) res.send({ message: "User registered successfully!" });
}
} catch (error) {
res.status(500).send({ message: error.message });
}
};
exports.signin = async (req, res) => {
try {
const user = await User.findOne({
where: {
username: req.body.username,
},
});
if (!user) {
return res.status(404).send({ message: "User Not found." });
}
const passwordIsValid = bcrypt.compareSync(
req.body.password,
user.password
);
if (!passwordIsValid) {
return res.status(401).send({
message: "Invalid Password!",
});
}
const token = jwt.sign({ id: user.id }, config.secret, {
expiresIn: 86400, // 24 hours
});
let authorities = [];
const roles = await user.getRoles();
for (let i = 0; i < roles.length; i++) {
authorities.push("ROLE_" + roles[i].name.toUpperCase());
}
req.session.token = token;
return res.status(200).send({
id: user.id,
username: user.username,
email: user.email,
roles: authorities,
});
} catch (error) {
return res.status(500).send({ message: error.message });
}
};
exports.signout = async (req, res) => {
try {
req.session = null;
return res.status(200).send({
message: "You've been signed out!"
});
} catch (err) {
this.next(err);
}
};
Ada 4 fungsi :
– /api/test/all untuk akses publik
– /api/test/user untuk pengguna yang masuk (peran: pengguna/moderator/admin)
– /api/test/mod untuk pengguna yang memiliki peran moderator
– /api/test/admin untuk pengguna yang memiliki peran admin
controllers/user.controller.js
exports.allAccess = (req, res) => {
res.status(200).send("Public Content.");
};
exports.userBoard = (req, res) => {
res.status(200).send("User Content.");
};
exports.adminBoard = (req, res) => {
res.status(200).send("Admin Content.");
};
exports.moderatorBoard = (req, res) => {
res.status(200).send("Moderator Content.");
};
9. Tentukan Routes
Authentication:
- POST
/api/auth/signup
- POST
/api/auth/signin
- POST
/api/auth/signout
routes/auth.routes.js
const { verifySignUp } = require("../middleware");
const controller = require("../controllers/auth.controller");
module.exports = function(app) {
app.use(function(req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"Origin, Content-Type, Accept"
);
next();
});
app.post(
"/api/auth/signup",
[
verifySignUp.checkDuplicateUsernameOrEmail,
verifySignUp.checkRolesExisted
],
controller.signup
);
app.post("/api/auth/signin", controller.signin);
app.post("/api/auth/signout", controller.signout);
};
Authorization:
- GET
/api/test/all
- GET
/api/test/user
for loggedin users (user/moderator/admin) - GET
/api/test/mod
for moderator - GET
/api/test/admin
for admin
routes/user.routes.js
const { authJwt } = require("../middleware");
const controller = require("../controllers/user.controller");
module.exports = function(app) {
app.use(function(req, res, next) {
res.header(
"Access-Control-Allow-Headers",
"Origin, Content-Type, Accept"
);
next();
});
app.get("/api/test/all", controller.allAccess);
app.get(
"/api/test/user",
[authJwt.verifyToken],
controller.userBoard
);
app.get(
"/api/test/mod",
[authJwt.verifyToken, authJwt.isModerator],
controller.moderatorBoard
);
app.get(
"/api/test/admin",
[authJwt.verifyToken, authJwt.isAdmin],
controller.adminBoard
);
};
jangan lupa untuk server.js tambahkan kode sebagai berikut:
...
// routes
require('./app/routes/auth.routes')(app);
require('./app/routes/user.routes')(app);
// set port, listen for requests
...
10. Run & Test
Jalankan aplikasi Node.js dengan perintah: node server.js
/signup

/api/test/all

/api/test/user

/api/auth/signin


– GET /api/test/user
– GET /api/test/mod
– GET /api/test/admin

Demikian tutorial kali ini yang bisa saya sampaikan semoga bermanfaat.
terimakasih.