Skip to content

Commit 7a96765

Browse files
committed
first commit
0 parents  commit 7a96765

17 files changed

+577
-0
lines changed

.gitignore

+2
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,2 @@
1+
node_modules
2+
package-lock.json

README.md

+57
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,57 @@
1+
# Node.js Express Login and Registration example with JWT
2+
3+
- Appropriate Flow for User Login and Registration with JWT Authentication
4+
- Node.js Express Architecture with CORS, Authentication & Authorization middlewares & Sequelize
5+
- How to configure Express routes to work with JWT
6+
- How to define Data Models and association for Authentication and Authorization
7+
- Way to use Sequelize to interact with MySQL Database
8+
9+
## User Registration, User Login and Authorization process.
10+
The diagram shows flow of how we implement User Registration, User Login and Authorization process.
11+
12+
![node-js-express-login-example-flow](node-js-express-login-example-flow.png)
13+
14+
For more detail, please visit:
15+
> [Node.js Express Login and Registration example with JWT](https://www.bezkoder.com/node-js-express-login-example/)
16+
17+
## More Practice:
18+
> [Build Node.js Rest APIs with Express, Sequelize & MySQL](https://www.bezkoder.com/node-js-express-sequelize-mysql/)
19+
20+
> [Server side Pagination in Node.js with Sequelize and MySQL](https://www.bezkoder.com/node-js-sequelize-pagination-mysql/)
21+
22+
> [Node.js Express File Upload Rest API example](https://www.bezkoder.com/node-js-express-file-upload/)
23+
24+
> [Node.js Express File Upload with Google Cloud Storage example](https://www.bezkoder.com/google-cloud-storage-nodejs-upload-file/)
25+
26+
> [Node.js JWT Authentication & Authorization example (using HTTP Headers)](https://www.bezkoder.com/node-js-jwt-authentication-mysql/)
27+
28+
> [Node.js JWT Authentication & Authorization example with MongoDB](https://www.bezkoder.com/node-js-mongodb-auth-jwt/)
29+
30+
Associations:
31+
> [Sequelize Associations: One-to-Many Relationship example](https://www.bezkoder.com/sequelize-associate-one-to-many/)
32+
33+
> [Sequelize Associations: Many-to-Many Relationship example](https://www.bezkoder.com/sequelize-associate-many-to-many/)
34+
35+
Deployment:
36+
> [Deploying/Hosting Node.js app on Heroku with MySQL database](https://www.bezkoder.com/deploy-node-js-app-heroku-cleardb-mysql/)
37+
38+
Integration on same Server/Port:
39+
> [Integrate Angular 8 with Node.js Express](https://www.bezkoder.com/integrate-angular-8-node-js/)
40+
41+
> [Integrate Angular 10 with Node.js Express](https://www.bezkoder.com/integrate-angular-10-node-js/)
42+
43+
> [Integrate Angular 12 with Node.js Express](https://www.bezkoder.com/integrate-angular-12-node-js/)
44+
45+
> [Integrate Vue with Node.js Express](https://www.bezkoder.com/serve-vue-app-express/)
46+
47+
> [Integrate React with Node.js Express](https://www.bezkoder.com/integrate-react-express-same-server-port/)
48+
49+
## Project setup
50+
```
51+
npm install
52+
```
53+
54+
### Run
55+
```
56+
node server.js
57+
```

app/config/auth.config.js

+3
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,3 @@
1+
module.exports = {
2+
secret: "bezkoder-secret-key"
3+
};

app/config/db.config.js

+13
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
module.exports = {
2+
HOST: "localhost",
3+
USER: "root",
4+
PASSWORD: "123456",
5+
DB: "testdb",
6+
dialect: "mysql",
7+
pool: {
8+
max: 5,
9+
min: 0,
10+
acquire: 30000,
11+
idle: 10000
12+
}
13+
};

app/controllers/auth.controller.js

+96
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,96 @@
1+
const db = require("../models");
2+
const config = require("../config/auth.config");
3+
const User = db.user;
4+
const Role = db.role;
5+
6+
const Op = db.Sequelize.Op;
7+
8+
const jwt = require("jsonwebtoken");
9+
const bcrypt = require("bcryptjs");
10+
11+
exports.signup = async (req, res) => {
12+
// Save User to Database
13+
try {
14+
const user = await User.create({
15+
username: req.body.username,
16+
email: req.body.email,
17+
password: bcrypt.hashSync(req.body.password, 8),
18+
});
19+
20+
if (req.body.roles) {
21+
const roles = await Role.findAll({
22+
where: {
23+
name: {
24+
[Op.or]: req.body.roles,
25+
},
26+
},
27+
});
28+
29+
const result = user.setRoles(roles);
30+
if (result) res.send({ message: "User registered successfully!" });
31+
} else {
32+
// user has role = 1
33+
const result = user.setRoles([1]);
34+
if (result) res.send({ message: "User registered successfully!" });
35+
}
36+
} catch (error) {
37+
res.status(500).send({ message: error.message });
38+
}
39+
};
40+
41+
exports.signin = async (req, res) => {
42+
try {
43+
const user = await User.findOne({
44+
where: {
45+
username: req.body.username,
46+
},
47+
});
48+
49+
if (!user) {
50+
return res.status(404).send({ message: "User Not found." });
51+
}
52+
53+
const passwordIsValid = bcrypt.compareSync(
54+
req.body.password,
55+
user.password
56+
);
57+
58+
if (!passwordIsValid) {
59+
return res.status(401).send({
60+
message: "Invalid Password!",
61+
});
62+
}
63+
64+
const token = jwt.sign({ id: user.id }, config.secret, {
65+
expiresIn: 86400, // 24 hours
66+
});
67+
68+
let authorities = [];
69+
const roles = await user.getRoles();
70+
for (let i = 0; i < roles.length; i++) {
71+
authorities.push("ROLE_" + roles[i].name.toUpperCase());
72+
}
73+
74+
req.session.token = token;
75+
76+
return res.status(200).send({
77+
id: user.id,
78+
username: user.username,
79+
email: user.email,
80+
roles: authorities,
81+
});
82+
} catch (error) {
83+
return res.status(500).send({ message: error.message });
84+
}
85+
};
86+
87+
exports.signout = async (req, res) => {
88+
try {
89+
req.session = null;
90+
return res.status(200).send({
91+
message: "You've been signed out!"
92+
});
93+
} catch (err) {
94+
this.next(err);
95+
}
96+
};

app/controllers/user.controller.js

+15
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,15 @@
1+
exports.allAccess = (req, res) => {
2+
res.status(200).send("Public Content.");
3+
};
4+
5+
exports.userBoard = (req, res) => {
6+
res.status(200).send("User Content.");
7+
};
8+
9+
exports.adminBoard = (req, res) => {
10+
res.status(200).send("Admin Content.");
11+
};
12+
13+
exports.moderatorBoard = (req, res) => {
14+
res.status(200).send("Moderator Content.");
15+
};

app/middleware/authJwt.js

+99
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,99 @@
1+
const jwt = require("jsonwebtoken");
2+
const config = require("../config/auth.config.js");
3+
const db = require("../models");
4+
const User = db.user;
5+
6+
verifyToken = (req, res, next) => {
7+
let token = req.session.token;
8+
9+
if (!token) {
10+
return res.status(403).send({
11+
message: "No token provided!",
12+
});
13+
}
14+
15+
jwt.verify(token, config.secret, (err, decoded) => {
16+
if (err) {
17+
return res.status(401).send({
18+
message: "Unauthorized!",
19+
});
20+
}
21+
req.userId = decoded.id;
22+
next();
23+
});
24+
};
25+
26+
isAdmin = async (req, res, next) => {
27+
try {
28+
const user = await User.findByPk(req.userId);
29+
const roles = await user.getRoles();
30+
31+
for (let i = 0; i < roles.length; i++) {
32+
if (roles[i].name === "admin") {
33+
return next();
34+
}
35+
}
36+
37+
return res.status(403).send({
38+
message: "Require Admin Role!",
39+
});
40+
} catch (error) {
41+
return res.status(500).send({
42+
message: "Unable to validate User role!",
43+
});
44+
}
45+
};
46+
47+
isModerator = async (req, res, next) => {
48+
try {
49+
const user = await User.findByPk(req.userId);
50+
const roles = await user.getRoles();
51+
52+
for (let i = 0; i < roles.length; i++) {
53+
if (roles[i].name === "moderator") {
54+
return next();
55+
}
56+
}
57+
58+
return res.status(403).send({
59+
message: "Require Moderator Role!",
60+
});
61+
} catch (error) {
62+
return res.status(500).send({
63+
message: "Unable to validate Moderator role!",
64+
});
65+
}
66+
};
67+
68+
isModeratorOrAdmin = async (req, res, next) => {
69+
try {
70+
const user = await User.findByPk(req.userId);
71+
const roles = await user.getRoles();
72+
73+
for (let i = 0; i < roles.length; i++) {
74+
if (roles[i].name === "moderator") {
75+
return next();
76+
}
77+
78+
if (roles[i].name === "admin") {
79+
return next();
80+
}
81+
}
82+
83+
return res.status(403).send({
84+
message: "Require Moderator or Admin Role!",
85+
});
86+
} catch (error) {
87+
return res.status(500).send({
88+
message: "Unable to validate Moderator or Admin role!",
89+
});
90+
}
91+
};
92+
93+
const authJwt = {
94+
verifyToken,
95+
isAdmin,
96+
isModerator,
97+
isModeratorOrAdmin,
98+
};
99+
module.exports = authJwt;

app/middleware/index.js

+7
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,7 @@
1+
const authJwt = require("./authJwt");
2+
const verifySignUp = require("./verifySignUp");
3+
4+
module.exports = {
5+
authJwt,
6+
verifySignUp
7+
};

app/middleware/verifySignUp.js

+61
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,61 @@
1+
const db = require("../models");
2+
const ROLES = db.ROLES;
3+
const User = db.user;
4+
5+
checkDuplicateUsernameOrEmail = async (req, res, next) => {
6+
try {
7+
// Username
8+
let user = await User.findOne({
9+
where: {
10+
username: req.body.username
11+
}
12+
});
13+
14+
if (user) {
15+
return res.status(400).send({
16+
message: "Failed! Username is already in use!"
17+
});
18+
}
19+
20+
// Email
21+
user = await User.findOne({
22+
where: {
23+
email: req.body.email
24+
}
25+
});
26+
27+
if (user) {
28+
return res.status(400).send({
29+
message: "Failed! Email is already in use!"
30+
});
31+
}
32+
33+
next();
34+
} catch (error) {
35+
return res.status(500).send({
36+
message: error.message
37+
});
38+
}
39+
};
40+
41+
checkRolesExisted = (req, res, next) => {
42+
if (req.body.roles) {
43+
for (let i = 0; i < req.body.roles.length; i++) {
44+
if (!ROLES.includes(req.body.roles[i])) {
45+
res.status(400).send({
46+
message: "Failed! Role does not exist = " + req.body.roles[i]
47+
});
48+
return;
49+
}
50+
}
51+
}
52+
53+
next();
54+
};
55+
56+
const verifySignUp = {
57+
checkDuplicateUsernameOrEmail,
58+
checkRolesExisted
59+
};
60+
61+
module.exports = verifySignUp;

0 commit comments

Comments
 (0)